summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore14
-rw-r--r--AUTHORS1
-rw-r--r--Makefile24
-rw-r--r--README34
-rw-r--r--_exts/ebicsdomain.py2
-rw-r--r--_exts/httpdomain/httpdomain.py1
-rw-r--r--_exts/taler_sphinx_theme/__init__.py166
-rw-r--r--_exts/taler_sphinx_theme/guzzle_sphinx_theme/comments.html16
-rw-r--r--_exts/taler_sphinx_theme/guzzle_sphinx_theme/globaltoc.html14
-rw-r--r--_exts/taler_sphinx_theme/guzzle_sphinx_theme/layout.html172
-rw-r--r--_exts/taler_sphinx_theme/guzzle_sphinx_theme/localtoc.html10
-rw-r--r--_exts/taler_sphinx_theme/guzzle_sphinx_theme/logo-text.html1
-rw-r--r--_exts/taler_sphinx_theme/guzzle_sphinx_theme/search.html48
-rw-r--r--_exts/taler_sphinx_theme/guzzle_sphinx_theme/searchbox.html15
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/css/bootstrap-theme.min.css7
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/css/bootstrap.min.css7
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.eotbin20290 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.svg229
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.ttfbin41236 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.woffbin23292 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.eotbin30858 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.svg251
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.ttfbin30680 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.woffbin19788 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.eotbin34166 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.svg251
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.ttfbin33960 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.woffbin21940 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.eotbin30602 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.svg251
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.ttfbin30404 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.woffbin19972 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.eotbin33758 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.svg251
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.ttfbin33532 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.woffbin21824 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.eotbin34798 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.svg251
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.ttfbin34612 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.woffbin22416 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.eotbin29794 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.svg252
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.ttfbin29612 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.woffbin19396 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.eotbin34578 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.svg252
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.ttfbin34368 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.woffbin22444 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.eotbin29934 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.svg252
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.ttfbin29744 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.woffbin19624 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.eotbin30350 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.svg251
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.ttfbin30156 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.woffbin19736 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.eotbin34866 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.svg251
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.ttfbin34644 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.woffbin22332 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/stylesheet.css136
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Black.eotbin111902 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Bold.eotbin113630 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-ExtraLight.eotbin112362 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Light.eotbin112866 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Regular.eotbin112354 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Semibold.eotbin113510 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/LICENSE.txt93
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Black.otfbin91216 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Bold.otfbin92760 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-ExtraLight.otfbin89720 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Light.otfbin91424 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Regular.otfbin91276 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Semibold.otfbin93144 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/README.md18
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/ReadMe.html72
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/SourceSerifProReadMe.html189
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Black.ttfbin111572 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Bold.ttfbin113320 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-ExtraLight.ttfbin112004 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Light.ttfbin112528 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Regular.ttfbin112048 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Semibold.ttfbin113168 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Black.otf.woffbin48788 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Bold.otf.woffbin51188 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-ExtraLight.otf.woffbin47136 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Light.otf.woffbin49672 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Regular.otf.woffbin48972 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Semibold.otf.woffbin51272 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Black.ttf.woffbin49496 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Bold.ttf.woffbin51924 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-ExtraLight.ttf.woffbin48784 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Light.ttf.woffbin50792 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Regular.ttf.woffbin49604 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Semibold.ttf.woffbin51772 -> 0 bytes
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/bower.json15
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/source-serif-pro.css65
-rw-r--r--_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/guzzle.css_t1037
-rw-r--r--_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/jquery.js5
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/jquery.min.map1
-rw-r--r--_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/js/bootstrap.js1951
-rwxr-xr-x_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/js/bootstrap.min.js6
-rw-r--r--_exts/taler_sphinx_theme/guzzle_sphinx_theme/theme.conf40
-rw-r--r--_static/custom.css15
-rw-r--r--_static/sample-pos-config.json2
-rw-r--r--arch-api.pngbin59189 -> 0 bytes
-rw-r--r--arch.pngbin40820 -> 0 bytes
-rw-r--r--backoffice-product-create.stock.svg16
-rw-r--r--backoffice-tip-create.confirmation.svg16
-rw-r--r--backoffice-tip-create.svg16
-rw-r--r--cf/captcha-payment.txt2
-rw-r--r--checklist-demo-upgrade.rst56
-rw-r--r--checklist-release.rst70
-rw-r--r--checklists/checklist-demo-upgrade.rst173
-rw-r--r--checklists/checklist-release.rst141
-rw-r--r--checklists/qa-0.10.rst233
-rw-r--r--checklists/qa-0.9.4.rst228
-rw-r--r--coin.pngbin96492 -> 0 bytes
-rw-r--r--conf.py794
-rw-r--r--contrib/ci/Containerfile23
-rwxr-xr-xcontrib/ci/jobs/0-build/build-docs.sh17
-rwxr-xr-xcontrib/ci/jobs/0-build/job.sh6
-rw-r--r--core/api-auditor.rst263
-rw-r--r--core/api-bank-access.rst160
-rw-r--r--core/api-bank-conversion-info.rst223
-rw-r--r--core/api-bank-integration.rst201
-rw-r--r--core/api-bank-revenue.rst (renamed from core/api-bank-merchant.rst)98
-rw-r--r--core/api-bank-wire.rst (renamed from core/api-wire.rst)194
-rw-r--r--core/api-challenger.rst495
-rw-r--r--core/api-common.rst779
-rw-r--r--core/api-corebank.rst1244
-rw-r--r--core/api-donau.rst615
-rw-r--r--core/api-error.rst1205
-rw-r--r--core/api-exchange.rst4129
-rw-r--r--core/api-mailbox.rst215
-rw-r--r--core/api-merchant.rst2493
-rw-r--r--core/api-overview.rst150
-rw-r--r--core/api-sync.rst29
-rw-r--r--core/api-taldir.rst258
-rw-r--r--core/errors.rst79
-rw-r--r--core/index-bank-apis.rst38
-rw-r--r--core/index.rst31
-rw-r--r--core/intro-bank-apis.rst134
-rw-r--r--core/taler-uri.rst149
-rw-r--r--core/tos.rst43
-rw-r--r--core/wireformats.rst62
-rw-r--r--design-documents/001-new-browser-integration.rst4
-rw-r--r--design-documents/002-wallet-exchange-management.rst11
-rw-r--r--design-documents/003-tos-rendering.rst22
-rw-r--r--design-documents/004-wallet-withdrawal-flow.rst8
-rw-r--r--design-documents/005-wallet-backup-sync.rst12
-rw-r--r--design-documents/006-extensions.rst223
-rw-r--r--design-documents/007-payment.rst4
-rw-r--r--design-documents/008-fees.rst8
-rw-r--r--design-documents/009-backup.rst4
-rw-r--r--design-documents/010-exchange-helpers.rst10
-rw-r--r--design-documents/011-auditor-db-sync.rst14
-rw-r--r--design-documents/012-fee-schedule-metrics.rst8
-rw-r--r--design-documents/013-peer-to-peer-payments.rst41
-rw-r--r--design-documents/014-merchant-backoffice-ui.rst12
-rw-r--r--design-documents/015-merchant-backoffice-routing.rst29
-rw-r--r--design-documents/016-backoffice-order-management.rst32
-rw-r--r--design-documents/017-backoffice-inventory-management.rst28
-rw-r--r--design-documents/018-contract-json.rst8
-rw-r--r--design-documents/019-wallet-backup-merge.rst4
-rw-r--r--design-documents/020-backoffice-rewards-management.rst (renamed from design-documents/020-backoffice-tips-management.rst)38
-rw-r--r--design-documents/021-exchange-key-continuity.rst4
-rw-r--r--design-documents/022-wallet-auditor-reports.rst54
-rw-r--r--design-documents/023-taler-kyc.rst1883
-rw-r--r--design-documents/024-age-restriction.rst830
-rw-r--r--design-documents/025-withdraw-from-wallet.rst66
-rw-r--r--design-documents/026-refund-fees.rst65
-rw-r--r--design-documents/027-sandboxing-taler.rst165
-rw-r--r--design-documents/028-deposit-policies.rst207
-rw-r--r--design-documents/029-mobile-ui.rst41
-rw-r--r--design-documents/030-offline-payments.rst99
-rw-r--r--design-documents/031-invoicing.rst195
-rw-r--r--design-documents/032-brandt-vickrey-auctions.rst312
-rw-r--r--design-documents/033-database.rst152
-rw-r--r--design-documents/034-wallet-db-migration.rst78
-rw-r--r--design-documents/035-regional-currencies.rst196
-rw-r--r--design-documents/036-currency-conversion-service.rst97
-rw-r--r--design-documents/037-wallet-transactions-lifecycle.rst1049
-rw-r--r--design-documents/038-demobanks-protocol-suppliers.rst158
-rw-r--r--design-documents/039-taler-browser-integration.rst195
-rw-r--r--design-documents/040-distro-packaging.rst139
-rw-r--r--design-documents/041-wallet-balance-amount-definitions.rst410
-rw-r--r--design-documents/042-synthetic-wallet-errors.rst57
-rw-r--r--design-documents/043-managing-prebuilt-artifacts.rst107
-rw-r--r--design-documents/044-ci-system.rst130
-rw-r--r--design-documents/045-kyc-inheritance.rst186
-rw-r--r--design-documents/046-mumimo-contracts.rst709
-rw-r--r--design-documents/047-stefan.rst172
-rw-r--r--design-documents/048-wallet-exchange-lifecycle.rst144
-rw-r--r--design-documents/049-auth.rst154
-rw-r--r--design-documents/050-libeufin-nexus.rst354
-rw-r--r--design-documents/051-fractional-digits.rst211
-rw-r--r--design-documents/052-libeufin-bank-2fa.rst136
-rw-r--r--design-documents/053-wallet-ui.rst1243
-rw-r--r--design-documents/054-dynamic-form.rst201
-rw-r--r--design-documents/055-wallet-problem-report.rst114
-rw-r--r--design-documents/999-template.rst11
-rw-r--r--design-documents/_svgs/escrow-flow.svg1
-rw-r--r--design-documents/index.rst39
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/10-empty-wallet-01.pngbin0 -> 199631 bytes
l---------design-documents/wallet-screenshots/ios-wallet/10-empty-wallet-latest.png1
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/11-balances-list-01.pngbin0 -> 320043 bytes
l---------design-documents/wallet-screenshots/ios-wallet/11-balances-list-latest.png1
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/READE22
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/add-exchange/1-balance.pngbin0 -> 30910 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/add-exchange/10-testkudos-in-the-list.pngbin0 -> 32709 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/add-exchange/11-select-test-kudos.pngbin0 -> 49363 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/add-exchange/2-click-get-cash.pngbin0 -> 36330 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/add-exchange/3-click-add-exchange.pngbin0 -> 42139 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/add-exchange/4-input-URL.pngbin0 -> 56001 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/add-exchange/5-click-next.pngbin0 -> 37919 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/add-exchange/6-review-tos.pngbin0 -> 72501 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/add-exchange/7-accept-tos.pngbin0 -> 37051 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/add-exchange/8-confirm.pngbin0 -> 30910 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/add-exchange/9-click-get-cash.pngbin0 -> 36330 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/deposit/1-balance.pngbin0 -> 35087 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/deposit/10-balance.pngbin0 -> 47824 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/deposit/2-click-send.pngbin0 -> 47464 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/deposit/3-click-deposit.pngbin0 -> 35569 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/deposit/4-click-add-account.pngbin0 -> 54335 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/deposit/5-complete-form.pngbin0 -> 60639 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/deposit/6-click-add.pngbin0 -> 59490 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/deposit/7-confirm-deposit.pngbin0 -> 60419 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/deposit/8-show-transaction.pngbin0 -> 65622 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/deposit/9-after-deposit-confirmed.pngbin0 -> 76645 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/dev-tools.pngbin0 -> 95380 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/invoice/1-balance.pngbin0 -> 36026 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/invoice/10-confirm-transfer.pngbin0 -> 55732 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/invoice/11-show-history.pngbin0 -> 49646 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/invoice/2-click-add.pngbin0 -> 48365 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/invoice/3-input-six.pngbin0 -> 48827 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/invoice/4-click-invoice.pngbin0 -> 62019 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/invoice/5-complete-form.pngbin0 -> 64943 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/invoice/6-create-invoice.pngbin0 -> 73127 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/invoice/7-copy-qr-open-qr-page.pngbin0 -> 48070 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/invoice/8-paste-URI.pngbin0 -> 63650 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/invoice/9-click-open.pngbin0 -> 52823 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/payment/1-load-shop.pngbin0 -> 2449960 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/payment/10-click-article-URL.pngbin0 -> 76691 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/payment/2-click-first-article.pngbin0 -> 83759 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/payment/3-confirm-payment.pngbin0 -> 442385 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/payment/4-click-refund.pngbin0 -> 101347 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/payment/5-click-request-refund.pngbin0 -> 41768 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/payment/6-accept-refund.pngbin0 -> 85837 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/payment/7-click-refund-detail.pngbin0 -> 69279 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/payment/8-show-history.pngbin0 -> 81889 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/payment/9-click-receipt.pngbin0 -> 85837 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/scan-qr-code.pngbin0 -> 36358 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/settings-developer-mode.pngbin0 -> 170233 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/settings-normal-mode.pngbin0 -> 47851 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/store-installed.pngbin0 -> 32548 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/store-payment.pngbin0 -> 28060 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/store-withdraw.pngbin0 -> 20772 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/transfer/1-initial-balance.pngbin0 -> 36311 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/transfer/10-open-URI.pngbin0 -> 51973 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/transfer/11-accept-transfer.pngbin0 -> 49787 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/transfer/12-show-history.pngbin0 -> 47985 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/transfer/2-click-send.pngbin0 -> 47235 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/transfer/3-amount-five.pngbin0 -> 47547 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/transfer/4-send-wallet.pngbin0 -> 56300 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/transfer/5-complete-form.pngbin0 -> 58617 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/transfer/6-confirm-transfer.pngbin0 -> 77092 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/transfer/7-show-history.pngbin0 -> 55329 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/transfer/8-scan-qr.pngbin0 -> 48384 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/transfer/9-paste-URI.pngbin0 -> 64510 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/withdrawal/10-transaction-completed.pngbin0 -> 44344 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/withdrawal/11-history-after-withdraw.pngbin0 -> 35260 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/withdrawal/2-empty-wallet.pngbin0 -> 29113 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/withdrawal/3-get-digital-cash.pngbin0 -> 36120 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/withdrawal/4-select-kudos.pngbin0 -> 47910 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/withdrawal/5-set-amount-five.pngbin0 -> 48389 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/withdrawal/6-withdraw-from-bank.pngbin0 -> 52203 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/withdrawal/7-review-tos.pngbin0 -> 69841 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/withdrawal/8-accept-tos.pngbin0 -> 50475 bytes
-rw-r--r--design-documents/wallet-screenshots/webex-wallet/withdrawal/9-confirm-withdraw.pngbin0 -> 148862 bytes
-rw-r--r--exchange-db.pngbin352589 -> 0 bytes
-rw-r--r--extract-tsdefs/.gitignore3
-rw-r--r--extract-tsdefs/README.md8
-rw-r--r--extract-tsdefs/extract.ts341
-rw-r--r--extract-tsdefs/foo3562
-rw-r--r--extract-tsdefs/myout.md2517
-rw-r--r--extract-tsdefs/package.json19
-rw-r--r--extract-tsdefs/pnpm-lock.yaml41
-rw-r--r--extract-tsdefs/tsconfig.json103
-rw-r--r--frags/about-taler.rst26
-rw-r--r--frags/apt-install-libeufin-bank.rst6
-rw-r--r--frags/apt-install-libeufin-nexus.rst6
-rw-r--r--frags/apt-install-taler-merchant.rst5
-rw-r--r--frags/common-conf-syntax.rst61
-rw-r--r--frags/configuration-format.rst75
-rw-r--r--frags/db-stores-sensitive-data.rst7
-rw-r--r--frags/deploying-tos.rst45
-rw-r--r--frags/ebics-setup.rst0
-rw-r--r--frags/install-before-check.rst6
-rw-r--r--frags/installing-challenger.rst1
-rw-r--r--frags/installing-debian.rst9
-rw-r--r--frags/installing-gnunet.rst7
-rw-r--r--frags/installing-taler-merchant.rst4
-rw-r--r--frags/installing-trisquel.rst4
-rw-r--r--frags/installing-ubuntu.rst17
-rw-r--r--frags/legal.rst183
-rw-r--r--frags/libeufin-config-cli.rst51
-rw-r--r--frags/list-of-dependencies.rst35
-rw-r--r--frags/nexus-ebics-setup.rst87
-rw-r--r--frags/regional-manual-architecture.rst48
-rw-r--r--frags/regional-manual-use.rst110
-rw-r--r--frags/regional-system-on.rst44
-rw-r--r--frags/semver.rst25
-rw-r--r--frags/using-taler-config.rst35
-rw-r--r--global-licensing.rst236
-rw-r--r--images/Makefile34
-rw-r--r--images/arch-api.dot (renamed from arch-api.dot)0
-rw-r--r--images/arch.dot (renamed from arch.dot)0
-rw-r--r--images/auditor-db.png (renamed from auditor-db.png)bin397630 -> 397630 bytes
-rw-r--r--images/backoffice-order-create.all-expanded.svg (renamed from backoffice-order-create.all-expanded.svg)0
-rw-r--r--images/backoffice-order-create.payment-section.svg (renamed from backoffice-order-create.payment-section.svg)2
-rw-r--r--images/backoffice-order-create.price-section.svg (renamed from backoffice-order-create.price-section.svg)0
-rw-r--r--images/backoffice-order-create.product-section.svg (renamed from backoffice-order-create.product-section.svg)0
-rw-r--r--images/backoffice-order-details.claimed.svg (renamed from backoffice-order-details.claimed.svg)0
-rw-r--r--images/backoffice-order-details.paid.svg (renamed from backoffice-order-details.paid.svg)0
-rw-r--r--images/backoffice-order-details.refunded.svg (renamed from backoffice-order-details.refunded.svg)0
-rw-r--r--images/backoffice-order-details.unpaid.svg (renamed from backoffice-order-details.unpaid.svg)0
-rw-r--r--images/backoffice-order-list.pagination.svg (renamed from backoffice-order-list.pagination.svg)0
-rw-r--r--images/backoffice-order-list.svg (renamed from backoffice-order-list.svg)0
-rw-r--r--images/backoffice-order-refund.already.svg (renamed from backoffice-order-refund.already.svg)0
-rw-r--r--images/backoffice-order-refund.svg (renamed from backoffice-order-refund.svg)0
-rw-r--r--images/backoffice-product-create.stock.svg16
-rw-r--r--images/backoffice-product-create.svg (renamed from backoffice-product-create.svg)0
-rw-r--r--images/backoffice-product-create.with-stock.svg (renamed from backoffice-product-create.with-stock.svg)0
-rw-r--r--images/backoffice-product-create.without-stock.svg (renamed from backoffice-product-create.without-stock.svg)0
-rw-r--r--images/backoffice-product-list.actions.svg (renamed from backoffice-product-list.actions.svg)0
-rw-r--r--images/backoffice-product-list.svg (renamed from backoffice-product-list.svg)0
-rw-r--r--images/backoffice-product-update.svg (renamed from backoffice-product-update.svg)0
-rw-r--r--images/backoffice-reserve-create.svg (renamed from backoffice-reserve-create.svg)0
-rw-r--r--images/backoffice-reserve-details.svg (renamed from backoffice-reserve-details.svg)0
-rw-r--r--images/backoffice-reserve-details.unfunded.svg (renamed from backoffice-reserve-details.unfunded.svg)0
-rw-r--r--images/backoffice-reserve-list.svg (renamed from backoffice-reserve-list.svg)0
-rw-r--r--images/backoffice-reward-create.confirmation.svg16
-rw-r--r--images/backoffice-reward-create.svg16
-rw-r--r--images/challenger.dot26
-rw-r--r--images/coin.dot (renamed from coin.dot)0
-rw-r--r--images/deposit.dot (renamed from deposit.dot)0
-rw-r--r--images/diagram.dot (renamed from diagram.dot)0
-rw-r--r--images/exchange-db.pngbin0 -> 716821 bytes
-rw-r--r--images/grafana-postgres-exporter.pngbin0 -> 244971 bytes
-rw-r--r--images/kuma.pngbin0 -> 244687 bytes
-rw-r--r--images/kyc-process.pdfbin0 -> 24633 bytes
-rw-r--r--images/kyc-process.pngbin0 -> 44435 bytes
-rw-r--r--images/kyc-process.tex58
-rw-r--r--images/merchant-db.png (renamed from merchant-db.png)bin469419 -> 469419 bytes
-rw-r--r--images/regional-arch.dot36
-rw-r--r--images/regional-arch.pngbin0 -> 117525 bytes
-rw-r--r--images/regional-currency-architecture-diagram.pngbin0 -> 117207 bytes
-rw-r--r--images/replication.png (renamed from replication.png)bin46376 -> 46376 bytes
-rw-r--r--images/replication.svg (renamed from replication.svg)0
-rw-r--r--images/reserve.dot (renamed from reserve.dot)0
-rw-r--r--images/taler-logo.svg1
-rw-r--r--images/taler-monitoring-infrastructure.pngbin0 -> 85006 bytes
-rw-r--r--images/transaction-common-states.dot52
-rw-r--r--images/transaction-common-states.svg16
-rw-r--r--images/transaction-deposit-states.dot44
-rw-r--r--images/transaction-payment-states.dot48
-rw-r--r--images/transaction-pull-credit-states.dot43
-rw-r--r--images/transaction-pull-debit-states.dot34
-rw-r--r--images/transaction-push-credit-states.dot37
-rw-r--r--images/transaction-push-debit-states.dot32
-rw-r--r--images/transaction-refresh-states.dot27
-rw-r--r--images/transaction-refund-states.dot8
-rw-r--r--images/transaction-withdrawal-states.dot45
-rw-r--r--images/transaction-withdrawal-states.svg16
-rw-r--r--images/uptime-kuma-edit.pngbin0 -> 116550 bytes
-rw-r--r--images/uptime-kuma-from-grafana.pngbin0 -> 345702 bytes
-rw-r--r--images/wallet-confirm-withdraw.svg16
-rw-r--r--images/wallet-mobile-overview.svg103
-rw-r--r--images/wallet-start-manual-withdraw.svg16
-rw-r--r--index.rst30
-rw-r--r--libeufin/api-nexus.rst1044
-rw-r--r--libeufin/api-sandbox.rst232
-rw-r--r--libeufin/bank-manual.rst307
-rw-r--r--libeufin/bank-transport-ebics.rst55
-rw-r--r--libeufin/banking-protocols.rst127
-rw-r--r--libeufin/camt.054-style-0.pngbin0 -> 61540 bytes
-rw-r--r--libeufin/camt.054-style-1.pngbin0 -> 247241 bytes
-rw-r--r--libeufin/check-payment-subject-0.pngbin0 -> 37554 bytes
-rw-r--r--libeufin/check-payment-subject-1.pngbin0 -> 102107 bytes
-rw-r--r--libeufin/concepts.rst166
-rw-r--r--libeufin/ebics.rst597
-rw-r--r--libeufin/enable-EBICS.pngbin0 -> 113808 bytes
-rw-r--r--libeufin/frontend.rst47
-rw-r--r--libeufin/get-EBICS-IDs-0.pngbin0 -> 68292 bytes
-rw-r--r--libeufin/get-EBICS-IDs-1.pngbin0 -> 158547 bytes
-rw-r--r--libeufin/index.rst37
-rw-r--r--libeufin/iso20022.rst213
-rw-r--r--libeufin/nexus-manual.rst277
-rw-r--r--libeufin/nexus-tutorial.rst631
-rw-r--r--libeufin/no-accounts.pngbin0 -> 122549 bytes
-rw-r--r--libeufin/regional-automated-manual.rst261
-rw-r--r--libeufin/regional-custom-manual.rst181
-rw-r--r--libeufin/sepa.rst26
-rw-r--r--libeufin/set-EBICS-keys.pngbin0 -> 143389 bytes
-rw-r--r--libeufin/set-IBAN.pngbin0 -> 98929 bytes
-rw-r--r--libeufin/set-ISO-2019-0.pngbin0 -> 39695 bytes
-rw-r--r--libeufin/set-ISO-2019-1.pngbin0 -> 115189 bytes
-rw-r--r--libeufin/set-english-and-register.pngbin0 -> 129003 bytes
-rw-r--r--libeufin/setup-ebics-at-postfinance.rst90
-rw-r--r--libeufin/transaction-identification.rst87
-rw-r--r--manpages/TDM.el172
-rw-r--r--manpages/TEMPLATE-148
-rw-r--r--manpages/challenger-admin.1.rst70
-rw-r--r--manpages/challenger-config.1.rst101
-rw-r--r--manpages/challenger-dbconfig.1.rst61
-rw-r--r--manpages/challenger-dbinit.1.rst65
-rw-r--r--manpages/challenger-httpd.1.rst61
-rw-r--r--manpages/challenger.conf.5.rst88
-rw-r--r--manpages/libeufin-bank.1.rst185
-rw-r--r--manpages/libeufin-bank.conf.5.rst146
-rw-r--r--manpages/libeufin-nexus.1.rst154
-rw-r--r--manpages/libeufin-nexus.conf.5.rst190
-rw-r--r--manpages/sync-config.1.rst101
-rw-r--r--manpages/sync-dbconfig.1.rst61
-rw-r--r--manpages/sync-dbinit.1.rst65
-rw-r--r--manpages/sync-httpd.1.rst78
-rw-r--r--manpages/sync.conf.5.rst92
-rw-r--r--manpages/taler-aggregator-benchmark.1.rst72
-rw-r--r--manpages/taler-auditor-dbconfig.1.rst61
-rw-r--r--manpages/taler-auditor-offline.1.rst2
-rw-r--r--manpages/taler-auditor.1.rst5
-rw-r--r--manpages/taler-bank-benchmark.1.rst26
-rw-r--r--manpages/taler-config.1.rst3
-rw-r--r--manpages/taler-exchange-aggregator.1.rst6
-rw-r--r--manpages/taler-exchange-benchmark.1.rst28
-rw-r--r--manpages/taler-exchange-dbconfig.1.rst61
-rw-r--r--manpages/taler-exchange-dbinit.1.rst4
-rw-r--r--manpages/taler-exchange-drain.1.rst56
-rw-r--r--manpages/taler-exchange-expire.1.rst66
-rw-r--r--manpages/taler-exchange-httpd.1.rst7
-rw-r--r--manpages/taler-exchange-kyc-aml-pep-trigger.1.rst35
-rw-r--r--manpages/taler-exchange-kyc-tester.1.rst93
-rw-r--r--manpages/taler-exchange-offline.1.rst232
-rw-r--r--manpages/taler-exchange-router.1.rst67
-rw-r--r--manpages/taler-exchange-secmod-cs.1.rst76
-rw-r--r--manpages/taler-exchange-wire-gateway-client.1.rst2
-rw-r--r--manpages/taler-exchange-wirewatch.1.rst8
-rw-r--r--manpages/taler-fakebank-run.1.rst6
-rw-r--r--manpages/taler-helper-auditor-purses.1.rst75
-rw-r--r--manpages/taler-mdb.1.rst73
-rw-r--r--manpages/taler-merchant-benchmark.1.rst13
-rw-r--r--manpages/taler-merchant-dbconfig.1.rst61
-rw-r--r--manpages/taler-merchant-depositcheck.1.rst78
-rw-r--r--manpages/taler-merchant-exchange.1.rst73
-rw-r--r--manpages/taler-merchant-httpd.1.rst7
-rw-r--r--manpages/taler-merchant-passwd.1.rst64
-rw-r--r--manpages/taler-merchant-setup-reserve.1.rst119
-rw-r--r--manpages/taler-merchant-webhook.1.rst68
-rw-r--r--manpages/taler-merchant-wirewatch.1.rst78
-rw-r--r--manpages/taler-terms-generator.1.rst72
-rw-r--r--manpages/taler-unified-setup.1.rst110
-rw-r--r--manpages/taler-wallet-cli.1.rst2
-rw-r--r--manpages/taler.conf.5.rst463
-rw-r--r--merchant-benchmark.conf3
-rw-r--r--merchant-spec/public-orders-get.ts2
-rw-r--r--orphaned/README2
-rw-r--r--orphaned/taler-mcig.rst (renamed from taler-mcig.rst)14
-rw-r--r--orphaned/taler-nfc-guide.rst (renamed from taler-nfc-guide.rst)16
-rw-r--r--python-guidelines.rst2
-rw-r--r--screenshots/create_orders.pngbin0 -> 131092 bytes
-rw-r--r--screenshots/cta-accept-tos-android-0.pngbin0 -> 118553 bytes
l---------screenshots/cta-accept-tos-android-latest.png1
-rw-r--r--screenshots/cta-accept-tos-chrome-0.pngbin0 -> 92439 bytes
l---------screenshots/cta-accept-tos-chrome-latest.png1
-rw-r--r--screenshots/cta-accept-tos-firefox-0.pngbin0 -> 105184 bytes
l---------screenshots/cta-accept-tos-firefox-latest.png1
-rw-r--r--screenshots/cta-accept-tos-ios-0.pngbin0 -> 116707 bytes
l---------screenshots/cta-accept-tos-ios-latest.png1
-rw-r--r--screenshots/cta-balance-list-android-0.pngbin0 -> 47885 bytes
l---------screenshots/cta-balance-list-android-latest.png1
-rw-r--r--screenshots/cta-balance-list-firefox-0.pngbin0 -> 44775 bytes
l---------screenshots/cta-balance-list-firefox-latest.png1
-rw-r--r--screenshots/cta-balance-list-ios-0.pngbin0 -> 316738 bytes
l---------screenshots/cta-balance-list-ios-latest.png1
-rw-r--r--screenshots/cta-deposit-1-ios-0.pngbin0 -> 155427 bytes
l---------screenshots/cta-deposit-1-ios-latest.png1
-rw-r--r--screenshots/cta-deposit-2-ios-0.pngbin0 -> 174391 bytes
l---------screenshots/cta-deposit-2-ios-latest.png1
-rw-r--r--screenshots/cta-deposit-android-0.pngbin0 -> 54746 bytes
l---------screenshots/cta-deposit-android-latest.png1
-rw-r--r--screenshots/cta-deposit-firefox-0.pngbin0 -> 59490 bytes
l---------screenshots/cta-deposit-firefox-latest.png1
-rw-r--r--screenshots/cta-payment-android-0.pngbin0 -> 59747 bytes
l---------screenshots/cta-payment-android-latest.png1
-rw-r--r--screenshots/cta-payment-chrome-0.pngbin0 -> 48539 bytes
l---------screenshots/cta-payment-chrome-latest.png1
-rw-r--r--screenshots/cta-payment-firefox-0.pngbin0 -> 43899 bytes
l---------screenshots/cta-payment-firefox-latest.png1
-rw-r--r--screenshots/cta-payment-ios-0.pngbin0 -> 198398 bytes
l---------screenshots/cta-payment-ios-latest.png1
-rw-r--r--screenshots/cta-payment-paid-android-0.pngbin0 -> 55338 bytes
l---------screenshots/cta-payment-paid-android-latest.png1
-rw-r--r--screenshots/cta-payment-paid-chrome-0.pngbin0 -> 41120 bytes
l---------screenshots/cta-payment-paid-chrome-latest.png1
-rw-r--r--screenshots/cta-payment-paid-firefox-0.pngbin0 -> 36529 bytes
l---------screenshots/cta-payment-paid-firefox-latest.png1
-rw-r--r--screenshots/cta-payment-paid-ios-0.pngbin0 -> 169485 bytes
l---------screenshots/cta-payment-paid-ios-latest.png1
-rw-r--r--screenshots/cta-peer-pull-initiate-android-0.pngbin0 -> 54340 bytes
l---------screenshots/cta-peer-pull-initiate-android-latest.png1
-rw-r--r--screenshots/cta-peer-pull-initiate-firefox-0.pngbin0 -> 62019 bytes
l---------screenshots/cta-peer-pull-initiate-firefox-latest.png1
-rw-r--r--screenshots/cta-peer-pull-initiate-ios-0.pngbin0 -> 186311 bytes
l---------screenshots/cta-peer-pull-initiate-ios-latest.png1
-rw-r--r--screenshots/cta-peer-push-initiate-android-0.pngbin0 -> 50363 bytes
l---------screenshots/cta-peer-push-initiate-android-latest.png1
-rw-r--r--screenshots/cta-peer-push-initiate-firefox-0.pngbin0 -> 56300 bytes
l---------screenshots/cta-peer-push-initiate-firefox-latest.png1
-rw-r--r--screenshots/cta-peer-push-initiate-ios-0.pngbin0 -> 176120 bytes
l---------screenshots/cta-peer-push-initiate-ios-latest.png1
-rw-r--r--screenshots/cta-transaction-list-android-0.pngbin0 -> 83906 bytes
l---------screenshots/cta-transaction-list-android-latest.png1
-rw-r--r--screenshots/cta-transaction-list-firefox-0.pngbin0 -> 47985 bytes
l---------screenshots/cta-transaction-list-firefox-latest.png1
-rw-r--r--screenshots/cta-transaction-list-ios-0.pngbin0 -> 474321 bytes
l---------screenshots/cta-transaction-list-ios-latest.png1
-rw-r--r--screenshots/cta-url-entry-android-0.pngbin0 -> 23916 bytes
l---------screenshots/cta-url-entry-android-latest.png1
-rw-r--r--screenshots/cta-url-entry-chrome-0.pngbin0 -> 44061 bytes
l---------screenshots/cta-url-entry-chrome-latest.png1
-rw-r--r--screenshots/cta-url-entry-firefox-0.pngbin0 -> 37619 bytes
l---------screenshots/cta-url-entry-firefox-latest.png1
-rw-r--r--screenshots/cta-wire-transfer-android-0.pngbin0 -> 123556 bytes
l---------screenshots/cta-wire-transfer-android-latest.png1
-rw-r--r--screenshots/cta-wire-transfer-chrome-0.pngbin0 -> 115131 bytes
l---------screenshots/cta-wire-transfer-chrome-latest.png1
-rw-r--r--screenshots/cta-wire-transfer-firefox-0.pngbin0 -> 75735 bytes
l---------screenshots/cta-wire-transfer-firefox-latest.png1
-rw-r--r--screenshots/cta-wire-transfer-ios-0.pngbin0 -> 533067 bytes
l---------screenshots/cta-wire-transfer-ios-latest.png1
-rw-r--r--screenshots/cta-withdraw-android-0.pngbin0 -> 286811 bytes
l---------screenshots/cta-withdraw-android-latest.png1
-rw-r--r--screenshots/cta-withdraw-chrome-0.pngbin0 -> 28593 bytes
l---------screenshots/cta-withdraw-chrome-latest.png1
-rw-r--r--screenshots/cta-withdraw-confirm-android-0.pngbin0 -> 43977 bytes
-rw-r--r--screenshots/cta-withdraw-confirm-chrome-0.pngbin0 -> 34371 bytes
-rw-r--r--screenshots/cta-withdraw-confirm-firefox-0.pngbin0 -> 50475 bytes
-rw-r--r--screenshots/cta-withdraw-confirm-ios-0.pngbin0 -> 193455 bytes
-rw-r--r--screenshots/cta-withdraw-done-android-0.pngbin0 -> 44643 bytes
l---------screenshots/cta-withdraw-done-android-latest.png1
-rw-r--r--screenshots/cta-withdraw-done-chrome-0.pngbin0 -> 31257 bytes
l---------screenshots/cta-withdraw-done-chrome-latest.png1
-rw-r--r--screenshots/cta-withdraw-done-firefox-0.pngbin0 -> 30061 bytes
l---------screenshots/cta-withdraw-done-firefox-latest.png1
-rw-r--r--screenshots/cta-withdraw-done-ios-0.pngbin0 -> 310883 bytes
l---------screenshots/cta-withdraw-done-ios-latest.png1
-rw-r--r--screenshots/cta-withdraw-firefox-0.pngbin0 -> 35550 bytes
-rw-r--r--screenshots/cta-withdraw-ios-0.pngbin0 -> 215793 bytes
l---------screenshots/cta-withdraw-ios-latest.png1
-rw-r--r--screenshots/cta-withdraw-review-android-0.pngbin0 -> 42897 bytes
l---------screenshots/cta-withdraw-review-android-latest.png1
-rw-r--r--screenshots/cta-withdraw-review-chrome-0.pngbin0 -> 36401 bytes
l---------screenshots/cta-withdraw-review-chrome-latest.png1
-rw-r--r--screenshots/enter_instance_details.pngbin0 -> 63262 bytes
-rw-r--r--screenshots/instance_iban_config.pngbin0 -> 59170 bytes
-rw-r--r--screenshots/merchant_first_login.pngbin0 -> 201140 bytes
-rw-r--r--screenshots/no_default_account_yet.pngbin0 -> 54464 bytes
-rw-r--r--screenshots/payment_links.pngbin0 -> 227921 bytes
-rw-r--r--taler-auditor-manual.rst106
-rw-r--r--taler-backoffice-manual.rst135
-rw-r--r--taler-bank-manual.rst71
-rw-r--r--taler-challenger-manual.rst686
-rw-r--r--taler-developer-manual.rst814
-rw-r--r--taler-exchange-manual.rst2232
-rw-r--r--taler-exchange-setup-guide.rst987
-rw-r--r--taler-merchant-api-tutorial.rst134
-rw-r--r--taler-merchant-manual.rst1563
-rw-r--r--taler-merchant-pos-terminal.rst51
-rw-r--r--taler-monitoring-infrastructure.rst197
-rw-r--r--taler-user-guide.rst328
-rw-r--r--taler-wallet-cli-manual.rst138
-rw-r--r--taler-wallet.rst1198
-rw-r--r--wallet/wallet-core.md4105
584 files changed, 43781 insertions, 18839 deletions
diff --git a/.gitignore b/.gitignore
index 2bd7e375..03767229 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,16 @@ _build
*.pyc
prebuilt
.vscode
-vtestenv/ \ No newline at end of file
+vtestenv/
+
+# generated images
+images/transaction-*.png
+images/arch-api.png
+images/coin.png
+images/deposit.png
+images/reserve.png
+*.png
+texinfo/
+
+!/design-documents/wallet-screenshots/**/*.png
+!/screenshots/*.png
diff --git a/AUTHORS b/AUTHORS
index aed0f6d8..25c1cc6b 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -3,3 +3,4 @@ Sree Harsha Totakura <sreeharsha@totakura.in>
Florian Dold
Christian Grothoff
Benedikt Muller
+Thien-Thi Nguyen (ttn)†
diff --git a/Makefile b/Makefile
index 5b6a8ddd..7d6aea04 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ 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. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
+$(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.
@@ -50,17 +50,9 @@ help:
clean:
rm -rf $(BUILDDIR)/*
-
-arch-api.png: arch-api.dot
- dot -Tpng arch-api.dot > arch-api.png
-coin.png: coin.dot
- dot -Tpng coin.dot > coin.png
-deposit.png: deposit.dot
- dot -Tpng deposit.dot > deposit.png
-reserve.png: reserve.dot
- dot -Tpng reserve.dot > reserve.png
-
-diagrams: arch-api.png coin.png
+.PHONY: diagrams
+diagrams:
+ $(MAKE) -C images/
# The html-linked builder does not support caching, so we
@@ -115,25 +107,25 @@ devhelp:
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/neuro"
@echo "# devhelp"
-epub:
+epub: diagrams
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
-latex:
+latex: diagrams
$(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:
+latexpdf: diagrams
$(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:
+latexpdfja: diagrams
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
diff --git a/README b/README
index b7f64144..9b892363 100644
--- a/README
+++ b/README
@@ -1,10 +1,34 @@
This repository contains the documentation for all main GNU Taler components.
-Before building the documentation, make sure that you have the required
-dependencies installed using pip3:
+To build things on a Debian (-based) system, install these packages:
+ - make
+ - python3-sphinx
+ - python3-recommonmark
+ - python3-sphinx-book-theme
+ - graphviz
+ - texlive-latex-extra
+ - dvipng
-$ pip3 install --user --upgrade recommonmark sphinx
+Then, do "make html" for HTML, "make texinfo" for Texinfo, etc.
+(Do "make" w/o a target to see a list of possible targets.)
-Note by Buck: when setting up on VM, I also needed:
+The output is in subdir ‘_build’.
-# apt install texlive-latex-extra graphviz
+
+Branch ‘prebuilt’ is special. Its contents (or a subset) are used as
+submodules in other Git repos (e.g., Exchange, Merchant, Sync).
+
+One approach that works well (so far) for ttn is to do
+(presuming that the current directory is named ‘docs’):
+
+ $ cd ..
+ $ git clone -b prebuilt --reference docs \
+ git+ssh://git@git.taler.net/docs.git \
+ docs-prebuilt
+
+This creates Git repo docs-prebuilt as a peer to the current repo.
+
+This way, you can build in this directory (i.e., "make man" or whatever)
+and then copy to ../docs-prebuilt/man/* what files need to be updated.
+In that repo, you can commit changes and push to git.taler.net as normal,
+all without having to do "git checkout" in either repo.
diff --git a/_exts/ebicsdomain.py b/_exts/ebicsdomain.py
index 4dcc30c1..3424cb57 100644
--- a/_exts/ebicsdomain.py
+++ b/_exts/ebicsdomain.py
@@ -169,6 +169,8 @@ class EbicsOrders(SphinxDirective):
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)
diff --git a/_exts/httpdomain/httpdomain.py b/_exts/httpdomain/httpdomain.py
index 59665a05..b31142b1 100644
--- a/_exts/httpdomain/httpdomain.py
+++ b/_exts/httpdomain/httpdomain.py
@@ -219,6 +219,7 @@ HTTP_STATUS_CODES = {
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
diff --git a/_exts/taler_sphinx_theme/__init__.py b/_exts/taler_sphinx_theme/__init__.py
deleted file mode 100644
index 2d3c61c4..00000000
--- a/_exts/taler_sphinx_theme/__init__.py
+++ /dev/null
@@ -1,166 +0,0 @@
-"""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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/comments.html b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/comments.html
deleted file mode 100644
index 42a95fb9..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/comments.html
+++ /dev/null
@@ -1,16 +0,0 @@
-{% 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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/globaltoc.html b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/globaltoc.html
deleted file mode 100644
index b2c04e27..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/globaltoc.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
-<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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/layout.html b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/layout.html
deleted file mode 100644
index 18c9e5b7..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/layout.html
+++ /dev/null
@@ -1,172 +0,0 @@
-{%- 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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/localtoc.html b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/localtoc.html
deleted file mode 100644
index 49f8e19a..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/localtoc.html
+++ /dev/null
@@ -1,10 +0,0 @@
-{%- 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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/logo-text.html b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/logo-text.html
deleted file mode 100644
index e52500e2..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/logo-text.html
+++ /dev/null
@@ -1 +0,0 @@
-<a href="{{ homepage() }}" class="text-logo">{{ theme_project_nav_name or shorttitle }}</a>
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/search.html b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/search.html
deleted file mode 100644
index 5d194d85..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/search.html
+++ /dev/null
@@ -1,48 +0,0 @@
-{%- 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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/searchbox.html b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/searchbox.html
deleted file mode 100644
index 7f574c3f..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/searchbox.html
+++ /dev/null
@@ -1,15 +0,0 @@
-{%- 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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/css/bootstrap-theme.min.css b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/css/bootstrap-theme.min.css
deleted file mode 100755
index f05c90c0..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/css/bootstrap-theme.min.css
+++ /dev/null
@@ -1,7 +0,0 @@
-/*!
- * 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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/css/bootstrap.min.css b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/css/bootstrap.min.css
deleted file mode 100755
index e6dfb8b4..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/css/bootstrap.min.css
+++ /dev/null
@@ -1,7 +0,0 @@
-/*!
- * 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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.eot b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.eot
deleted file mode 100755
index 423bd5d3..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.eot
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.svg b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.svg
deleted file mode 100755
index 44694887..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.svg
+++ /dev/null
@@ -1,229 +0,0 @@
-<?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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.ttf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.ttf
deleted file mode 100755
index a498ef4e..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.ttf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.woff
deleted file mode 100755
index d83c539b..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.eot b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.eot
deleted file mode 100755
index 5d4a1c47..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.eot
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.svg b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.svg
deleted file mode 100755
index 7cda1026..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.svg
+++ /dev/null
@@ -1,251 +0,0 @@
-<?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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.ttf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.ttf
deleted file mode 100755
index 7ab5d85b..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.ttf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.woff
deleted file mode 100755
index 869a9ed8..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.eot b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.eot
deleted file mode 100755
index ad651807..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.eot
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.svg b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.svg
deleted file mode 100755
index 91491201..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.svg
+++ /dev/null
@@ -1,251 +0,0 @@
-<?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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.ttf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.ttf
deleted file mode 100755
index 6a30fa9d..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.ttf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.woff
deleted file mode 100755
index 46778a21..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.eot b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.eot
deleted file mode 100755
index 2f7ae28d..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.eot
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.svg b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.svg
deleted file mode 100755
index 009e1d7b..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.svg
+++ /dev/null
@@ -1,251 +0,0 @@
-<?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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.ttf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.ttf
deleted file mode 100755
index dacc5bbb..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.ttf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.woff
deleted file mode 100755
index de4f8e77..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.eot b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.eot
deleted file mode 100755
index e4f4ab0d..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.eot
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.svg b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.svg
deleted file mode 100755
index a0612586..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.svg
+++ /dev/null
@@ -1,251 +0,0 @@
-<?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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.ttf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.ttf
deleted file mode 100755
index 7e636eb4..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.ttf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.woff
deleted file mode 100755
index f81b2161..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.eot b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.eot
deleted file mode 100755
index c3159521..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.eot
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.svg b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.svg
deleted file mode 100755
index be508574..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.svg
+++ /dev/null
@@ -1,251 +0,0 @@
-<?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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.ttf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.ttf
deleted file mode 100755
index cb3fda65..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.ttf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.woff
deleted file mode 100755
index 03eaf586..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.eot b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.eot
deleted file mode 100755
index f17617e0..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.eot
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.svg b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.svg
deleted file mode 100755
index deadc3ef..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.svg
+++ /dev/null
@@ -1,252 +0,0 @@
-<?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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.ttf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.ttf
deleted file mode 100755
index b83078a6..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.ttf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.woff
deleted file mode 100755
index ff882b6a..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.eot b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.eot
deleted file mode 100755
index 95c6c619..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.eot
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.svg b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.svg
deleted file mode 100755
index 1ac169c0..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.svg
+++ /dev/null
@@ -1,252 +0,0 @@
-<?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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.ttf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.ttf
deleted file mode 100755
index 3162ff8e..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.ttf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.woff
deleted file mode 100755
index f6e97d5a..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.eot b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.eot
deleted file mode 100755
index 545b7c15..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.eot
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.svg b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.svg
deleted file mode 100755
index 46a8f4c6..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.svg
+++ /dev/null
@@ -1,252 +0,0 @@
-<?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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.ttf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.ttf
deleted file mode 100755
index a5b2378e..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.ttf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.woff
deleted file mode 100755
index 11698afc..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.eot b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.eot
deleted file mode 100755
index acc32c42..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.eot
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.svg b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.svg
deleted file mode 100755
index ef8b7a2b..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.svg
+++ /dev/null
@@ -1,251 +0,0 @@
-<?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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.ttf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.ttf
deleted file mode 100755
index a5b9691c..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.ttf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.woff
deleted file mode 100755
index 17fb5dc3..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.eot b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.eot
deleted file mode 100755
index 0048da00..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.eot
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.svg b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.svg
deleted file mode 100755
index 46cfd5c8..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.svg
+++ /dev/null
@@ -1,251 +0,0 @@
-<?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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.ttf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.ttf
deleted file mode 100755
index 61d58bfa..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.ttf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.woff
deleted file mode 100755
index 611b3902..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/stylesheet.css b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/stylesheet.css
deleted file mode 100755
index 8a9f79bf..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/stylesheet.css
+++ /dev/null
@@ -1,136 +0,0 @@
-/***** 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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Black.eot b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Black.eot
deleted file mode 100755
index b6f111e0..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Black.eot
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Bold.eot b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Bold.eot
deleted file mode 100755
index 94d75e9d..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Bold.eot
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-ExtraLight.eot b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-ExtraLight.eot
deleted file mode 100755
index 3ab1eec3..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-ExtraLight.eot
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Light.eot b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Light.eot
deleted file mode 100755
index 8b580d38..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Light.eot
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Regular.eot b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Regular.eot
deleted file mode 100755
index f7315435..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Regular.eot
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Semibold.eot b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Semibold.eot
deleted file mode 100755
index 13c0f8e4..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Semibold.eot
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/LICENSE.txt b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/LICENSE.txt
deleted file mode 100755
index 6cb6facf..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/LICENSE.txt
+++ /dev/null
@@ -1,93 +0,0 @@
-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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Black.otf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Black.otf
deleted file mode 100755
index d63bde76..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Black.otf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Bold.otf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Bold.otf
deleted file mode 100755
index 11429501..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Bold.otf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-ExtraLight.otf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-ExtraLight.otf
deleted file mode 100755
index 9cd91d86..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-ExtraLight.otf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Light.otf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Light.otf
deleted file mode 100755
index 0ba7bf75..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Light.otf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Regular.otf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Regular.otf
deleted file mode 100755
index ad044c73..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Regular.otf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Semibold.otf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Semibold.otf
deleted file mode 100755
index 76a41f74..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Semibold.otf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/README.md b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/README.md
deleted file mode 100755
index a3cf79e2..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/README.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# 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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/ReadMe.html b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/ReadMe.html
deleted file mode 100755
index 1aeb7755..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/ReadMe.html
+++ /dev/null
@@ -1,72 +0,0 @@
-<!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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/SourceSerifProReadMe.html b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/SourceSerifProReadMe.html
deleted file mode 100755
index da1f9e57..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/SourceSerifProReadMe.html
+++ /dev/null
@@ -1,189 +0,0 @@
-<!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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Black.ttf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Black.ttf
deleted file mode 100755
index bfa258b9..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Black.ttf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Bold.ttf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Bold.ttf
deleted file mode 100755
index 4e8b4293..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Bold.ttf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-ExtraLight.ttf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-ExtraLight.ttf
deleted file mode 100755
index ae8e2ed3..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-ExtraLight.ttf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Light.ttf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Light.ttf
deleted file mode 100755
index 1fd150b4..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Light.ttf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Regular.ttf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Regular.ttf
deleted file mode 100755
index 62fedd61..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Regular.ttf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Semibold.ttf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Semibold.ttf
deleted file mode 100755
index 78c178fd..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Semibold.ttf
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Black.otf.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Black.otf.woff
deleted file mode 100755
index 9044ee91..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Black.otf.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Bold.otf.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Bold.otf.woff
deleted file mode 100755
index a907b533..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Bold.otf.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-ExtraLight.otf.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-ExtraLight.otf.woff
deleted file mode 100755
index b990a76e..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-ExtraLight.otf.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Light.otf.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Light.otf.woff
deleted file mode 100755
index 6d6c4bad..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Light.otf.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Regular.otf.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Regular.otf.woff
deleted file mode 100755
index a6fbe17f..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Regular.otf.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Semibold.otf.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Semibold.otf.woff
deleted file mode 100755
index 68471798..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Semibold.otf.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Black.ttf.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Black.ttf.woff
deleted file mode 100755
index db1b1f66..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Black.ttf.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Bold.ttf.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Bold.ttf.woff
deleted file mode 100755
index 056a5ad3..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Bold.ttf.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-ExtraLight.ttf.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-ExtraLight.ttf.woff
deleted file mode 100755
index 53b296dc..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-ExtraLight.ttf.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Light.ttf.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Light.ttf.woff
deleted file mode 100755
index b8de7138..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Light.ttf.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Regular.ttf.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Regular.ttf.woff
deleted file mode 100755
index 84f37774..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Regular.ttf.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Semibold.ttf.woff b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Semibold.ttf.woff
deleted file mode 100755
index 3ba49931..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Semibold.ttf.woff
+++ /dev/null
Binary files differ
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/bower.json b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/bower.json
deleted file mode 100755
index 4775f7c3..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/bower.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/source-serif-pro.css b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/source-serif-pro.css
deleted file mode 100755
index 697763fc..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/source-serif-pro.css
+++ /dev/null
@@ -1,65 +0,0 @@
-@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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/guzzle.css_t b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/guzzle.css_t
deleted file mode 100644
index 6164129a..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/guzzle.css_t
+++ /dev/null
@@ -1,1037 +0,0 @@
-/* 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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/jquery.js b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/jquery.js
deleted file mode 100644
index c6a59aeb..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/jquery.js
+++ /dev/null
@@ -1,5 +0,0 @@
-/*! 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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/jquery.min.map b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/jquery.min.map
deleted file mode 100755
index 7137d892..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/jquery.min.map
+++ /dev/null
@@ -1 +0,0 @@
-{"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":"CAaA,SAAWA,EAAQC,GAOnB,GAECC,GAGAC,EAIAC,QAA2BH,GAG3BI,EAAWL,EAAOK,SAClBC,EAAWN,EAAOM,SAGlBC,EAAUP,EAAOQ,OAGjBC,EAAKT,EAAOU,EAGZC,KAGAC,KAEAC,EAAe,QAGfC,EAAcF,EAAgBG,OAC9BC,EAAYJ,EAAgBK,KAC5BC,EAAaN,EAAgBO,MAC7BC,EAAeR,EAAgBS,QAC/BC,EAAgBX,EAAWY,SAC3BC,EAAcb,EAAWc,eACzBC,EAAYb,EAAac,KAGzBnB,EAAS,SAAUoB,EAAUC,GAE5B,MAAO,IAAIrB,GAAOsB,GAAGC,KAAMH,EAAUC,EAAS1B,IAI/C6B,EAAY,sCAAsCC,OAGlDC,EAAiB,OAGjBC,EAAQ,qCAKRC,EAAa,mCAGbC,EAAa,6BAGbC,EAAc,gBACdC,EAAe,uBACfC,EAAe,qCACfC,EAAe,kEAGfC,EAAY,QACZC,EAAa,eAGbC,EAAa,SAAUC,EAAKC,GAC3B,MAAOA,GAAOC,eAIfC,EAAY,SAAUC,IAGhB5C,EAAS6C,kBAAmC,SAAfD,EAAME,MAA2C,aAAxB9C,EAAS+C,cACnEC,IACA7C,EAAO8C,UAITD,EAAS,WACHhD,EAAS6C,kBACb7C,EAASkD,oBAAqB,mBAAoBP,GAAW,GAC7DhD,EAAOuD,oBAAqB,OAAQP,GAAW,KAG/C3C,EAASmD,YAAa,qBAAsBR,GAC5ChD,EAAOwD,YAAa,SAAUR,IAIjCxC,GAAOsB,GAAKtB,EAAOiD,WAElBC,OAAQ7C,EAER8C,YAAanD,EACbuB,KAAM,SAAUH,EAAUC,EAAS1B,GAClC,GAAIyD,GAAOC,CAGX,KAAMjC,EACL,MAAOkC,KAIR,IAAyB,gBAAblC,GAAwB,CAUnC,GAPCgC,EAF2B,MAAvBhC,EAASmC,OAAO,IAAyD,MAA3CnC,EAASmC,OAAQnC,EAASoC,OAAS,IAAepC,EAASoC,QAAU,GAE7F,KAAMpC,EAAU,MAGlBQ,EAAW6B,KAAMrC,IAIrBgC,IAAUA,EAAM,IAAO/B,EAqDrB,OAAMA,GAAWA,EAAQ6B,QACtB7B,GAAW1B,GAAa+D,KAAMtC,GAKhCkC,KAAKH,YAAa9B,GAAUqC,KAAMtC,EAxDzC,IAAKgC,EAAM,GAAK,CAWf,GAVA/B,EAAUA,YAAmBrB,GAASqB,EAAQ,GAAKA,EAGnDrB,EAAO2D,MAAOL,KAAMtD,EAAO4D,UAC1BR,EAAM,GACN/B,GAAWA,EAAQwC,SAAWxC,EAAQyC,eAAiBzC,EAAUxB,GACjE,IAIIgC,EAAWkC,KAAMX,EAAM,KAAQpD,EAAOgE,cAAe3C,GACzD,IAAM+B,IAAS/B,GAETrB,EAAOiE,WAAYX,KAAMF,IAC7BE,KAAMF,GAAS/B,EAAS+B,IAIxBE,KAAKY,KAAMd,EAAO/B,EAAS+B,GAK9B,OAAOE,MAQP,GAJAD,EAAOxD,EAASsE,eAAgBf,EAAM,IAIjCC,GAAQA,EAAKe,WAAa,CAG9B,GAAKf,EAAKgB,KAAOjB,EAAM,GACtB,MAAOzD,GAAW+D,KAAMtC,EAIzBkC,MAAKE,OAAS,EACdF,KAAK,GAAKD,EAKX,MAFAC,MAAKjC,QAAUxB,EACfyD,KAAKlC,SAAWA,EACTkC,KAcH,MAAKlC,GAASyC,UACpBP,KAAKjC,QAAUiC,KAAK,GAAKlC,EACzBkC,KAAKE,OAAS,EACPF,MAIItD,EAAOiE,WAAY7C,GACvBzB,EAAWmD,MAAO1B,IAGrBA,EAASA,WAAa3B,IAC1B6D,KAAKlC,SAAWA,EAASA,SACzBkC,KAAKjC,QAAUD,EAASC,SAGlBrB,EAAOsE,UAAWlD,EAAUkC,QAIpClC,SAAU,GAGVoC,OAAQ,EAGRe,KAAM,WACL,MAAOjB,MAAKE,QAGbgB,QAAS,WACR,MAAO9D,GAAW+D,KAAMnB,OAKzBoB,IAAK,SAAUC,GACd,MAAc,OAAPA,EAGNrB,KAAKkB,UAGG,EAANG,EAAUrB,KAAMA,KAAKE,OAASmB,GAAQrB,KAAMqB,IAKhDC,UAAW,SAAUC,GAGpB,GAAIC,GAAM9E,EAAO2D,MAAOL,KAAKH,cAAe0B,EAO5C,OAJAC,GAAIC,WAAazB,KACjBwB,EAAIzD,QAAUiC,KAAKjC,QAGZyD,GAMRE,KAAM,SAAUC,EAAUC,GACzB,MAAOlF,GAAOgF,KAAM1B,KAAM2B,EAAUC,IAGrCpC,MAAO,SAAUxB,GAIhB,MAFAtB,GAAO8C,MAAMqC,UAAUC,KAAM9D,GAEtBgC,MAGR3C,MAAO,WACN,MAAO2C,MAAKsB,UAAWlE,EAAW2E,MAAO/B,KAAMgC,aAGhDC,MAAO,WACN,MAAOjC,MAAKkC,GAAI,IAGjBC,KAAM,WACL,MAAOnC,MAAKkC,GAAI,KAGjBA,GAAI,SAAUE,GACb,GAAIC,GAAMrC,KAAKE,OACdoC,GAAKF,GAAU,EAAJA,EAAQC,EAAM,EAC1B,OAAOrC,MAAKsB,UAAWgB,GAAK,GAASD,EAAJC,GAAYtC,KAAKsC,SAGnDC,IAAK,SAAUZ,GACd,MAAO3B,MAAKsB,UAAW5E,EAAO6F,IAAIvC,KAAM,SAAUD,EAAMqC,GACvD,MAAOT,GAASR,KAAMpB,EAAMqC,EAAGrC,OAIjCyC,IAAK,WACJ,MAAOxC,MAAKyB,YAAczB,KAAKH,YAAY,OAK5C1C,KAAMD,EACNuF,QAASA,KACTC,UAAWA,QAIZhG,EAAOsB,GAAGC,KAAK0B,UAAYjD,EAAOsB,GAElCtB,EAAOiG,OAASjG,EAAOsB,GAAG2E,OAAS,WAClC,GAAIC,GAAKC,EAAaC,EAAMC,EAAMC,EAASC,EAC1CC,EAASlB,UAAU,OACnBI,EAAI,EACJlC,EAAS8B,UAAU9B,OACnBiD,GAAO,CAqBR,KAlBuB,iBAAXD,KACXC,EAAOD,EACPA,EAASlB,UAAU,OAEnBI,EAAI,GAIkB,gBAAXc,IAAwBxG,EAAOiE,WAAWuC,KACrDA,MAIIhD,IAAWkC,IACfc,EAASlD,OACPoC,GAGSlC,EAAJkC,EAAYA,IAEnB,GAAmC,OAA7BY,EAAUhB,UAAWI,IAE1B,IAAMW,IAAQC,GACbJ,EAAMM,EAAQH,GACdD,EAAOE,EAASD,GAGXG,IAAWJ,IAKXK,GAAQL,IAAUpG,EAAOgE,cAAcoC,KAAUD,EAAcnG,EAAO0G,QAAQN,MAC7ED,GACJA,GAAc,EACdI,EAAQL,GAAOlG,EAAO0G,QAAQR,GAAOA,MAGrCK,EAAQL,GAAOlG,EAAOgE,cAAckC,GAAOA,KAI5CM,EAAQH,GAASrG,EAAOiG,OAAQQ,EAAMF,EAAOH,IAGlCA,IAAS3G,IACpB+G,EAAQH,GAASD,GAOrB,OAAOI,IAGRxG,EAAOiG,QACNU,WAAY,SAAUF,GASrB,MARKjH,GAAOU,IAAMF,IACjBR,EAAOU,EAAID,GAGPwG,GAAQjH,EAAOQ,SAAWA,IAC9BR,EAAOQ,OAASD,GAGVC,GAIR4G,SAAS,EAITC,UAAW,EAGXC,UAAW,SAAUC,GACfA,EACJ/G,EAAO6G,YAEP7G,EAAO8C,OAAO,IAKhBA,MAAO,SAAUkE,GAGhB,GAAKA,KAAS,KAAShH,EAAO6G,WAAY7G,EAAO4G,QAAjD,CAKA,IAAM/G,EAASoH,KACd,MAAOC,YAAYlH,EAAO8C,MAI3B9C,GAAO4G,SAAU,EAGZI,KAAS,KAAUhH,EAAO6G,UAAY,IAK3CnH,EAAUyH,YAAatH,GAAYG,IAG9BA,EAAOsB,GAAG8F,SACdpH,EAAQH,GAAWuH,QAAQ,SAASC,IAAI,YAO1CpD,WAAY,SAAUqD,GACrB,MAA4B,aAArBtH,EAAO2C,KAAK2E,IAGpBZ,QAASa,MAAMb,SAAW,SAAUY,GACnC,MAA4B,UAArBtH,EAAO2C,KAAK2E,IAGpBE,SAAU,SAAUF,GACnB,MAAc,OAAPA,GAAeA,GAAOA,EAAI9H,QAGlCiI,UAAW,SAAUH,GACpB,OAAQI,MAAOC,WAAWL,KAAUM,SAAUN,IAG/C3E,KAAM,SAAU2E,GACf,MAAY,OAAPA,EACWA,EAARO,GAEc,gBAARP,IAAmC,kBAARA,GACxCnH,EAAYW,EAAc2D,KAAK6C,KAAU,eAClCA,IAGTtD,cAAe,SAAUsD,GAIxB,IAAMA,GAA4B,WAArBtH,EAAO2C,KAAK2E,IAAqBA,EAAIzD,UAAY7D,EAAOwH,SAAUF,GAC9E,OAAO,CAGR,KAEC,GAAKA,EAAInE,cACPnC,EAAYyD,KAAK6C,EAAK,iBACtBtG,EAAYyD,KAAK6C,EAAInE,YAAYF,UAAW,iBAC7C,OAAO,EAEP,MAAQ6E,GAET,OAAO,EAMR,GAAIC,EACJ,KAAMA,IAAOT,IAEb,MAAOS,KAAQtI,GAAauB,EAAYyD,KAAM6C,EAAKS,IAGpDC,cAAe,SAAUV,GACxB,GAAIjB,EACJ,KAAMA,IAAQiB,GACb,OAAO,CAER,QAAO,GAGRW,MAAO,SAAUC,GAChB,KAAUC,OAAOD,IAMlBtE,UAAW,SAAUwE,EAAM/G,EAASgH,GACnC,IAAMD,GAAwB,gBAATA,GACpB,MAAO,KAEgB,kBAAZ/G,KACXgH,EAAchH,EACdA,GAAU,GAEXA,EAAUA,GAAWxB,CAErB,IAAIyI,GAASzG,EAAW4B,KAAM2E,GAC7BG,GAAWF,KAGZ,OAAKC,IACKjH,EAAQmH,cAAeF,EAAO,MAGxCA,EAAStI,EAAOyI,eAAiBL,GAAQ/G,EAASkH,GAC7CA,GACJvI,EAAQuI,GAAUG,SAEZ1I,EAAO2D,SAAW2E,EAAOK,cAGjCC,UAAW,SAAUR,GAEpB,MAAK5I,GAAOqJ,MAAQrJ,EAAOqJ,KAAKC,MACxBtJ,EAAOqJ,KAAKC,MAAOV,GAGb,OAATA,EACGA,EAGa,gBAATA,KAGXA,EAAOpI,EAAOmB,KAAMiH,GAEfA,GAGCtG,EAAYiC,KAAMqE,EAAKW,QAAS/G,EAAc,KACjD+G,QAAS9G,EAAc,KACvB8G,QAAShH,EAAc,MAEXiH,SAAU,UAAYZ,MAKtCpI,EAAOiI,MAAO,iBAAmBG,GAAjCpI,IAIDiJ,SAAU,SAAUb,GACnB,GAAIc,GAAKC,CACT,KAAMf,GAAwB,gBAATA,GACpB,MAAO,KAER,KACM5I,EAAO4J,WACXD,EAAM,GAAIC,WACVF,EAAMC,EAAIE,gBAAiBjB,EAAO,cAElCc,EAAM,GAAII,eAAe,oBACzBJ,EAAIK,MAAQ,QACZL,EAAIM,QAASpB,IAEb,MAAON,GACRoB,EAAMzJ,EAKP,MAHMyJ,IAAQA,EAAIO,kBAAmBP,EAAIQ,qBAAsB,eAAgBlG,QAC9ExD,EAAOiI,MAAO,gBAAkBG,GAE1Bc,GAGRS,KAAM,aAKNC,WAAY,SAAUxB,GAChBA,GAAQpI,EAAOmB,KAAMiH,KAIvB5I,EAAOqK,YAAc,SAAUzB,GAChC5I,EAAe,KAAEiF,KAAMjF,EAAQ4I,KAC3BA,IAMP0B,UAAW,SAAUC,GACpB,MAAOA,GAAOhB,QAAS7G,EAAW,OAAQ6G,QAAS5G,EAAYC,IAGhE4H,SAAU,SAAU3G,EAAMgD,GACzB,MAAOhD,GAAK2G,UAAY3G,EAAK2G,SAASC,gBAAkB5D,EAAK4D,eAI9DjF,KAAM,SAAUsC,EAAKrC,EAAUC,GAC9B,GAAIgF,GACHxE,EAAI,EACJlC,EAAS8D,EAAI9D,OACbkD,EAAUyD,EAAa7C,EAExB,IAAKpC,GACJ,GAAKwB,GACJ,KAAYlD,EAAJkC,EAAYA,IAGnB,GAFAwE,EAAQjF,EAASI,MAAOiC,EAAK5B,GAAKR,GAE7BgF,KAAU,EACd,UAIF,KAAMxE,IAAK4B,GAGV,GAFA4C,EAAQjF,EAASI,MAAOiC,EAAK5B,GAAKR,GAE7BgF,KAAU,EACd,UAOH,IAAKxD,GACJ,KAAYlD,EAAJkC,EAAYA,IAGnB,GAFAwE,EAAQjF,EAASR,KAAM6C,EAAK5B,GAAKA,EAAG4B,EAAK5B,IAEpCwE,KAAU,EACd,UAIF,KAAMxE,IAAK4B,GAGV,GAFA4C,EAAQjF,EAASR,KAAM6C,EAAK5B,GAAKA,EAAG4B,EAAK5B,IAEpCwE,KAAU,EACd,KAMJ,OAAO5C,IAIRnG,KAAMD,IAAcA,EAAUuD,KAAK,gBAClC,SAAU2F,GACT,MAAe,OAARA,EACN,GACAlJ,EAAUuD,KAAM2F,IAIlB,SAAUA,GACT,MAAe,OAARA,EACN,IACEA,EAAO,IAAKrB,QAASpH,EAAO,KAIjC2C,UAAW,SAAU+F,EAAKC,GACzB,GAAIxF,GAAMwF,KAaV,OAXY,OAAPD,IACCF,EAAaI,OAAOF,IACxBrK,EAAO2D,MAAOmB,EACE,gBAARuF,IACLA,GAAQA,GAGX7J,EAAUiE,KAAMK,EAAKuF,IAIhBvF,GAGR0F,QAAS,SAAUnH,EAAMgH,EAAK3E,GAC7B,GAAIC,EAEJ,IAAK0E,EAAM,CACV,GAAKzJ,EACJ,MAAOA,GAAa6D,KAAM4F,EAAKhH,EAAMqC,EAMtC,KAHAC,EAAM0E,EAAI7G,OACVkC,EAAIA,EAAQ,EAAJA,EAAQ+E,KAAKC,IAAK,EAAG/E,EAAMD,GAAMA,EAAI,EAEjCC,EAAJD,EAASA,IAEhB,GAAKA,IAAK2E,IAAOA,EAAK3E,KAAQrC,EAC7B,MAAOqC,GAKV,MAAO,IAGR/B,MAAO,SAAU4B,EAAOoF,GACvB,GAAIC,GAAID,EAAOnH,OACdkC,EAAIH,EAAM/B,OACVoC,EAAI,CAEL,IAAkB,gBAANgF,GACX,KAAYA,EAAJhF,EAAOA,IACdL,EAAOG,KAAQiF,EAAQ/E,OAGxB,OAAQ+E,EAAO/E,KAAOnG,EACrB8F,EAAOG,KAAQiF,EAAQ/E,IAMzB,OAFAL,GAAM/B,OAASkC,EAERH,GAGRsF,KAAM,SAAUhG,EAAOI,EAAU6F,GAChC,GAAIC,GACHjG,KACAY,EAAI,EACJlC,EAASqB,EAAMrB,MAKhB,KAJAsH,IAAQA,EAIItH,EAAJkC,EAAYA,IACnBqF,IAAW9F,EAAUJ,EAAOa,GAAKA,GAC5BoF,IAAQC,GACZjG,EAAIrE,KAAMoE,EAAOa,GAInB,OAAOZ,IAIRe,IAAK,SAAUhB,EAAOI,EAAU+F,GAC/B,GAAId,GACHxE,EAAI,EACJlC,EAASqB,EAAMrB,OACfkD,EAAUyD,EAAatF,GACvBC,IAGD,IAAK4B,EACJ,KAAYlD,EAAJkC,EAAYA,IACnBwE,EAAQjF,EAAUJ,EAAOa,GAAKA,EAAGsF,GAEnB,MAATd,IACJpF,EAAKA,EAAItB,QAAW0G,OAMtB,KAAMxE,IAAKb,GACVqF,EAAQjF,EAAUJ,EAAOa,GAAKA,EAAGsF,GAEnB,MAATd,IACJpF,EAAKA,EAAItB,QAAW0G,EAMvB,OAAO5J,GAAY+E,SAAWP,IAI/BmG,KAAM,EAINC,MAAO,SAAU5J,EAAID,GACpB,GAAI6D,GAAMgG,EAAO/B,CAUjB,OARwB,gBAAZ9H,KACX8H,EAAM7H,EAAID,GACVA,EAAUC,EACVA,EAAK6H,GAKAnJ,EAAOiE,WAAY3C,IAKzB4D,EAAOxE,EAAW+D,KAAMa,UAAW,GACnC4F,EAAQ,WACP,MAAO5J,GAAG+D,MAAOhE,GAAWiC,KAAM4B,EAAK3E,OAAQG,EAAW+D,KAAMa,cAIjE4F,EAAMD,KAAO3J,EAAG2J,KAAO3J,EAAG2J,MAAQjL,EAAOiL,OAElCC,GAZCzL,GAiBT0L,OAAQ,SAAUtG,EAAOvD,EAAIyG,EAAKmC,EAAOkB,EAAWC,EAAUC,GAC7D,GAAI5F,GAAI,EACPlC,EAASqB,EAAMrB,OACf+H,EAAc,MAAPxD,CAGR,IAA4B,WAAvB/H,EAAO2C,KAAMoF,GAAqB,CACtCqD,GAAY,CACZ,KAAM1F,IAAKqC,GACV/H,EAAOmL,OAAQtG,EAAOvD,EAAIoE,EAAGqC,EAAIrC,IAAI,EAAM2F,EAAUC,OAIhD,IAAKpB,IAAUzK,IACrB2L,GAAY,EAENpL,EAAOiE,WAAYiG,KACxBoB,GAAM,GAGFC,IAECD,GACJhK,EAAGmD,KAAMI,EAAOqF,GAChB5I,EAAK,OAILiK,EAAOjK,EACPA,EAAK,SAAU+B,EAAM0E,EAAKmC,GACzB,MAAOqB,GAAK9G,KAAMzE,EAAQqD,GAAQ6G,MAKhC5I,GACJ,KAAYkC,EAAJkC,EAAYA,IACnBpE,EAAIuD,EAAMa,GAAIqC,EAAKuD,EAAMpB,EAAQA,EAAMzF,KAAMI,EAAMa,GAAIA,EAAGpE,EAAIuD,EAAMa,GAAIqC,IAK3E,OAAOqD,GACNvG,EAGA0G,EACCjK,EAAGmD,KAAMI,GACTrB,EAASlC,EAAIuD,EAAM,GAAIkD,GAAQsD,GAGlCG,IAAK,WACJ,OAAO,GAAMC,OAASC,aAIxB1L,EAAO8C,MAAMqC,QAAU,SAAUmC,GAChC,IAAM5H,EAOL,GALAA,EAAYM,EAAO2L,WAKU,aAAxB9L,EAAS+C,WAEbsE,WAAYlH,EAAO8C,WAGb,IAAKjD,EAAS6C,iBAEpB7C,EAAS6C,iBAAkB,mBAAoBF,GAAW,GAG1DhD,EAAOkD,iBAAkB,OAAQF,GAAW,OAGtC,CAEN3C,EAAS+L,YAAa,qBAAsBpJ,GAG5ChD,EAAOoM,YAAa,SAAUpJ,EAI9B,IAAIqJ,IAAM,CAEV,KACCA,EAA6B,MAAvBrM,EAAOsM,cAAwBjM,EAAS4J,gBAC7C,MAAM3B,IAEH+D,GAAOA,EAAIE,UACf,QAAUC,KACT,IAAMhM,EAAO4G,QAAU,CAEtB,IAGCiF,EAAIE,SAAS,QACZ,MAAMjE,GACP,MAAOZ,YAAY8E,EAAe,IAInCnJ,IAGA7C,EAAO8C,YAMZ,MAAOpD,GAAUyF,QAASmC,IAI3BtH,EAAOgF,KAAK,gEAAgEiH,MAAM,KAAM,SAASvG,EAAGW,GACnGlG,EAAY,WAAakG,EAAO,KAAQA,EAAK4D,eAG9C,SAASE,GAAa7C,GACrB,GAAI9D,GAAS8D,EAAI9D,OAChBb,EAAO3C,EAAO2C,KAAM2E,EAErB,OAAKtH,GAAOwH,SAAUF,IACd,EAGc,IAAjBA,EAAIzD,UAAkBL,GACnB,EAGQ,UAATb,GAA6B,aAATA,IACb,IAAXa,GACgB,gBAAXA,IAAuBA,EAAS,GAAOA,EAAS,IAAO8D,IAIhE3H,EAAaK,EAAOH,EAEpB,IAAIqM,KAGJ,SAASC,GAAe7F,GACvB,GAAI8F,GAASF,EAAc5F,KAI3B,OAHAtG,GAAOgF,KAAMsB,EAAQlD,MAAO1B,OAAwB,SAAU2K,EAAGC,GAChEF,EAAQE,IAAS,IAEXF,EAyBRpM,EAAOuM,UAAY,SAAUjG,GAI5BA,EAA6B,gBAAZA,GACd4F,EAAc5F,IAAa6F,EAAe7F,GAC5CtG,EAAOiG,UAAYK,EAEpB,IACCkG,GAEAC,EAEAC,EAEAC,EAEAC,EAEAC,EAEAC,KAEAC,GAASzG,EAAQ0G,SAEjBC,EAAO,SAAU7E,GAOhB,IANAqE,EAASnG,EAAQmG,QAAUrE,EAC3BsE,GAAQ,EACRE,EAAcC,GAAe,EAC7BA,EAAc,EACdF,EAAeG,EAAKtJ,OACpBgJ,GAAS,EACDM,GAAsBH,EAAdC,EAA4BA,IAC3C,GAAKE,EAAMF,GAAcvH,MAAO+C,EAAM,GAAKA,EAAM,OAAU,GAAS9B,EAAQ4G,YAAc,CACzFT,GAAS,CACT,OAGFD,GAAS,EACJM,IACCC,EACCA,EAAMvJ,QACVyJ,EAAMF,EAAMI,SAEFV,EACXK,KAEAM,EAAKC,YAKRD,GAECE,IAAK,WACJ,GAAKR,EAAO,CAEX,GAAIS,GAAQT,EAAKtJ,QACjB,QAAU8J,GAAKpI,GACdlF,EAAOgF,KAAME,EAAM,SAAUmH,EAAGrB,GAC/B,GAAIrI,GAAO3C,EAAO2C,KAAMqI,EACV,cAATrI,EACE2D,EAAQkH,QAAWJ,EAAKK,IAAKzC,IAClC8B,EAAKrM,KAAMuK,GAEDA,GAAOA,EAAIxH,QAAmB,WAATb,GAEhC2K,EAAKtC,OAGJ1F,WAGCkH,EACJG,EAAeG,EAAKtJ,OAGTiJ,IACXI,EAAcU,EACdN,EAAMR,IAGR,MAAOnJ,OAGRoF,OAAQ,WAkBP,MAjBKoE,IACJ9M,EAAOgF,KAAMM,UAAW,SAAU+G,EAAGrB,GACpC,GAAI0C,EACJ,QAASA,EAAQ1N,EAAOwK,QAASQ,EAAK8B,EAAMY,IAAY,GACvDZ,EAAK9G,OAAQ0H,EAAO,GAEflB,IACUG,GAATe,GACJf,IAEaC,GAATc,GACJd,OAMEtJ,MAIRmK,IAAK,SAAUnM,GACd,MAAOA,GAAKtB,EAAOwK,QAASlJ,EAAIwL,GAAS,MAASA,IAAQA,EAAKtJ,SAGhEmK,MAAO,WAEN,MADAb,MACOxJ,MAGR+J,QAAS,WAER,MADAP,GAAOC,EAAQN,EAAShN,EACjB6D,MAGRsK,SAAU,WACT,OAAQd,GAGTe,KAAM,WAKL,MAJAd,GAAQtN,EACFgN,GACLW,EAAKC,UAEC/J,MAGRwK,OAAQ,WACP,OAAQf,GAGTgB,SAAU,SAAU1M,EAAS6D,GAU5B,MATAA,GAAOA,MACPA,GAAS7D,EAAS6D,EAAKvE,MAAQuE,EAAKvE,QAAUuE,IACzC4H,GAAWJ,IAASK,IACnBP,EACJO,EAAMtM,KAAMyE,GAEZ+H,EAAM/H,IAGD5B,MAGR2J,KAAM,WAEL,MADAG,GAAKW,SAAUzK,KAAMgC,WACdhC,MAGRoJ,MAAO,WACN,QAASA,GAIZ,OAAOU,IAERpN,EAAOiG,QAEN0F,SAAU,SAAUqC,GACnB,GAAIC,KAEA,UAAW,OAAQjO,EAAOuM,UAAU,eAAgB,aACpD,SAAU,OAAQvM,EAAOuM,UAAU,eAAgB,aACnD,SAAU,WAAYvM,EAAOuM,UAAU,YAE1C2B,EAAQ,UACR/I,GACC+I,MAAO,WACN,MAAOA,IAERC,OAAQ,WAEP,MADAC,GAAShJ,KAAME,WAAY+I,KAAM/I,WAC1BhC,MAERgL,KAAM,WACL,GAAIC,GAAMjJ,SACV,OAAOtF,GAAO2L,SAAS,SAAU6C,GAChCxO,EAAOgF,KAAMiJ,EAAQ,SAAUvI,EAAG+I,GACjC,GAAIC,GAASD,EAAO,GACnBnN,EAAKtB,EAAOiE,WAAYsK,EAAK7I,KAAS6I,EAAK7I,EAE5C0I,GAAUK,EAAM,IAAK,WACpB,GAAIE,GAAWrN,GAAMA,EAAG+D,MAAO/B,KAAMgC,UAChCqJ,IAAY3O,EAAOiE,WAAY0K,EAASxJ,SAC5CwJ,EAASxJ,UACPC,KAAMoJ,EAASI,SACfP,KAAMG,EAASK,QACfC,SAAUN,EAASO,QAErBP,EAAUE,EAAS,QAAUpL,OAAS6B,EAAUqJ,EAASrJ,UAAY7B,KAAMhC,GAAOqN,GAAarJ,eAIlGiJ,EAAM,OACJpJ,WAIJA,QAAS,SAAUmC,GAClB,MAAc,OAAPA,EAActH,EAAOiG,OAAQqB,EAAKnC,GAAYA,IAGvDiJ,IAwCD,OArCAjJ,GAAQ6J,KAAO7J,EAAQmJ,KAGvBtO,EAAOgF,KAAMiJ,EAAQ,SAAUvI,EAAG+I,GACjC,GAAI3B,GAAO2B,EAAO,GACjBQ,EAAcR,EAAO,EAGtBtJ,GAASsJ,EAAM,IAAO3B,EAAKQ,IAGtB2B,GACJnC,EAAKQ,IAAI,WAERY,EAAQe,GAGNhB,EAAY,EAAJvI,GAAS,GAAI2H,QAASY,EAAQ,GAAK,GAAIJ,MAInDO,EAAUK,EAAM,IAAO,WAEtB,MADAL,GAAUK,EAAM,GAAK,QAAUnL,OAAS8K,EAAWjJ,EAAU7B,KAAMgC,WAC5DhC,MAER8K,EAAUK,EAAM,GAAK,QAAW3B,EAAKiB,WAItC5I,EAAQA,QAASiJ,GAGZJ,GACJA,EAAKvJ,KAAM2J,EAAUA,GAIfA,GAIRc,KAAM,SAAUC,GACf,GAAIzJ,GAAI,EACP0J,EAAgB1O,EAAW+D,KAAMa,WACjC9B,EAAS4L,EAAc5L,OAGvB6L,EAAuB,IAAX7L,GAAkB2L,GAAenP,EAAOiE,WAAYkL,EAAYhK,SAAc3B,EAAS,EAGnG4K,EAAyB,IAAdiB,EAAkBF,EAAcnP,EAAO2L,WAGlD2D,EAAa,SAAU5J,EAAG6J,EAAUC,GACnC,MAAO,UAAUtF,GAChBqF,EAAU7J,GAAMpC,KAChBkM,EAAQ9J,GAAMJ,UAAU9B,OAAS,EAAI9C,EAAW+D,KAAMa,WAAc4E,EAChEsF,IAAWC,EACdrB,EAASsB,WAAYH,EAAUC,KACfH,GAChBjB,EAASjH,YAAaoI,EAAUC,KAKnCC,EAAgBE,EAAkBC,CAGnC,IAAKpM,EAAS,EAIb,IAHAiM,EAAqBlI,MAAO/D,GAC5BmM,EAAuBpI,MAAO/D,GAC9BoM,EAAsBrI,MAAO/D,GACjBA,EAAJkC,EAAYA,IACd0J,EAAe1J,IAAO1F,EAAOiE,WAAYmL,EAAe1J,GAAIP,SAChEiK,EAAe1J,GAAIP,UACjBC,KAAMkK,EAAY5J,EAAGkK,EAAiBR,IACtCf,KAAMD,EAASS,QACfC,SAAUQ,EAAY5J,EAAGiK,EAAkBF,MAE3CJ,CAUL,OAJMA,IACLjB,EAASjH,YAAayI,EAAiBR,GAGjChB,EAASjJ,aAGlBnF,EAAO6P,QAAU,WAEhB,GAAIA,GAASxN,EAAKyN,EACjBC,EAAOC,EAAQC,EACfC,EAAKC,EAAWC,EAAa1K,EAC7B2K,EAAMxQ,EAAS2I,cAAc,MAS9B,IANA6H,EAAIC,aAAc,YAAa,KAC/BD,EAAIE,UAAY,qEAGhBlO,EAAMgO,EAAI3G,qBAAqB,KAC/BoG,EAAIO,EAAI3G,qBAAqB,KAAM,IAC7BrH,IAAQyN,IAAMzN,EAAImB,OACvB,QAIDwM,GAASnQ,EAAS2I,cAAc,UAChC0H,EAAMF,EAAOQ,YAAa3Q,EAAS2I,cAAc,WACjDuH,EAAQM,EAAI3G,qBAAqB,SAAU,GAE3CoG,EAAEW,MAAMC,QAAU,gCAClBb,GAECc,gBAAmC,MAAlBN,EAAIO,UAGrBC,kBAA+C,IAA5BR,EAAIS,WAAWjN,SAIlCkN,OAAQV,EAAI3G,qBAAqB,SAASlG,OAI1CwN,gBAAiBX,EAAI3G,qBAAqB,QAAQlG,OAIlDiN,MAAO,MAAM1M,KAAM+L,EAAEmB,aAAa,UAIlCC,eAA2C,OAA3BpB,EAAEmB,aAAa,QAK/BE,QAAS,OAAOpN,KAAM+L,EAAEW,MAAMU,SAI9BC,WAAYtB,EAAEW,MAAMW,SAGpBC,UAAWtB,EAAM7F,MAIjBoH,YAAapB,EAAIqB,SAGjBC,UAAW3R,EAAS2I,cAAc,QAAQgJ,QAI1CC,WAA0E,kBAA9D5R,EAAS2I,cAAc,OAAOkJ,WAAW,GAAOC,UAG5DC,SAAkC,eAAxB/R,EAASgS,WAGnBC,eAAe,EACfC,cAAc,EACdC,wBAAwB,EACxBC,kBAAkB,EAClBC,qBAAqB,EACrBC,mBAAmB,EACnBC,eAAe,GAIhBrC,EAAMsC,SAAU,EAChBxC,EAAQyC,eAAiBvC,EAAM2B,WAAW,GAAOW,QAIjDrC,EAAOpC,UAAW,EAClBiC,EAAQ0C,aAAerC,EAAItC,QAG3B,WACQyC,GAAItM,KACV,MAAO+D,GACR+H,EAAQiC,eAAgB,EAIzB/B,EAAQlQ,EAAS2I,cAAc,SAC/BuH,EAAMO,aAAc,QAAS,IAC7BT,EAAQE,MAA0C,KAAlCA,EAAMkB,aAAc,SAGpClB,EAAM7F,MAAQ,IACd6F,EAAMO,aAAc,OAAQ,SAC5BT,EAAQ2C,WAA6B,MAAhBzC,EAAM7F,MAG3B6F,EAAMO,aAAc,UAAW,KAC/BP,EAAMO,aAAc,OAAQ,KAE5BL,EAAWpQ,EAAS4S,yBACpBxC,EAASO,YAAaT,GAItBF,EAAQ6C,cAAgB3C,EAAMsC,QAG9BxC,EAAQ8C,WAAa1C,EAASyB,WAAW,GAAOA,WAAW,GAAOkB,UAAUP,QAKvEhC,EAAIzE,cACRyE,EAAIzE,YAAa,UAAW,WAC3BiE,EAAQkC,cAAe,IAGxB1B,EAAIqB,WAAW,GAAOmB,QAKvB,KAAMnN,KAAOoN,QAAQ,EAAMC,QAAQ,EAAMC,SAAS,GACjD3C,EAAIC,aAAcH,EAAY,KAAOzK,EAAG,KAExCmK,EAASnK,EAAI,WAAcyK,IAAa3Q,IAAU6Q,EAAI4C,WAAY9C,GAAY+C,WAAY,CAmG3F,OAhGA7C,GAAII,MAAM0C,eAAiB,cAC3B9C,EAAIqB,WAAW,GAAOjB,MAAM0C,eAAiB,GAC7CtD,EAAQuD,gBAA+C,gBAA7B/C,EAAII,MAAM0C,eAGpCnT,EAAO,WACN,GAAIqT,GAAWC,EAAWC,EACzBC,EAAW,+HACXvM,EAAOpH,EAAS6J,qBAAqB,QAAQ,EAExCzC,KAKNoM,EAAYxT,EAAS2I,cAAc,OACnC6K,EAAU5C,MAAMC,QAAU,gFAE1BzJ,EAAKuJ,YAAa6C,GAAY7C,YAAaH,GAS3CA,EAAIE,UAAY,8CAChBgD,EAAMlD,EAAI3G,qBAAqB,MAC/B6J,EAAK,GAAI9C,MAAMC,QAAU,2CACzBN,EAA0C,IAA1BmD,EAAK,GAAIE,aAEzBF,EAAK,GAAI9C,MAAMiD,QAAU,GACzBH,EAAK,GAAI9C,MAAMiD,QAAU,OAIzB7D,EAAQ8D,sBAAwBvD,GAA2C,IAA1BmD,EAAK,GAAIE,aAG1DpD,EAAIE,UAAY,GAChBF,EAAII,MAAMC,QAAU,wKACpBb,EAAQ+D,UAAkC,IAApBvD,EAAIwD,YAC1BhE,EAAQiE,iCAAwD,IAAnB7M,EAAK8M,UAG7CvU,EAAOwU,mBACXnE,EAAQuC,cAAuE,QAArD5S,EAAOwU,iBAAkB3D,EAAK,WAAexE,IACvEgE,EAAQsC,kBAA2F,SAArE3S,EAAOwU,iBAAkB3D,EAAK,QAAY4D,MAAO,QAAUA,MAMzFX,EAAYjD,EAAIG,YAAa3Q,EAAS2I,cAAc,QACpD8K,EAAU7C,MAAMC,QAAUL,EAAII,MAAMC,QAAU8C,EAC9CF,EAAU7C,MAAMyD,YAAcZ,EAAU7C,MAAMwD,MAAQ,IACtD5D,EAAII,MAAMwD,MAAQ,MAElBpE,EAAQqC,qBACNvK,YAAcnI,EAAOwU,iBAAkBV,EAAW,WAAeY,oBAGxD7D,GAAII,MAAM0D,OAASvU,IAK9ByQ,EAAIE,UAAY,GAChBF,EAAII,MAAMC,QAAU8C,EAAW,8CAC/B3D,EAAQmC,uBAA+C,IAApB3B,EAAIwD,YAIvCxD,EAAII,MAAMiD,QAAU,QACpBrD,EAAIE,UAAY,cAChBF,EAAIS,WAAWL,MAAMwD,MAAQ,MAC7BpE,EAAQoC,iBAAyC,IAApB5B,EAAIwD,YAE5BhE,EAAQmC,yBAIZ/K,EAAKwJ,MAAM0D,KAAO,IAIpBlN,EAAKmN,YAAaf,GAGlBA,EAAYhD,EAAMkD,EAAMD,EAAY,QAIrCjR,EAAM2N,EAASC,EAAWC,EAAMJ,EAAIC,EAAQ,KAErCF,IAGR,IAAIwE,GAAS,+BACZC,EAAa,UAEd,SAASC,GAAclR,EAAMgD,EAAM+B,EAAMoM,GACxC,GAAMxU,EAAOyU,WAAYpR,GAAzB,CAIA,GAAIqR,GAAW5P,EACd6P,EAAc3U,EAAOkT,QACrB0B,EAA4B,gBAATvO,GAInBwO,EAASxR,EAAKQ,SAIdiR,EAAQD,EAAS7U,EAAO8U,MAAQzR,EAIhCgB,EAAKwQ,EAASxR,EAAMsR,GAAgBtR,EAAMsR,IAAiBA,CAI5D,IAAOtQ,GAAOyQ,EAAMzQ,KAASmQ,GAAQM,EAAMzQ,GAAI+D,QAAUwM,GAAaxM,IAAS3I,EAoE/E,MAhEM4E,KAGAwQ,EACJxR,EAAMsR,GAAgBtQ,EAAKjE,EAAgB2U,OAAS/U,EAAOiL,OAE3D5G,EAAKsQ,GAIDG,EAAOzQ,KACZyQ,EAAOzQ,MAIDwQ,IACLC,EAAOzQ,GAAK2Q,OAAShV,EAAO2J,QAMT,gBAATtD,IAAqC,kBAATA,MAClCmO,EACJM,EAAOzQ,GAAOrE,EAAOiG,OAAQ6O,EAAOzQ,GAAMgC,GAE1CyO,EAAOzQ,GAAK+D,KAAOpI,EAAOiG,OAAQ6O,EAAOzQ,GAAK+D,KAAM/B,IAItDqO,EAAYI,EAAOzQ,GAKbmQ,IACCE,EAAUtM,OACfsM,EAAUtM,SAGXsM,EAAYA,EAAUtM,MAGlBA,IAAS3I,IACbiV,EAAW1U,EAAO8J,UAAWzD,IAAW+B,GAKpCwM,GAGJ9P,EAAM4P,EAAWrO,GAGL,MAAPvB,IAGJA,EAAM4P,EAAW1U,EAAO8J,UAAWzD,MAGpCvB,EAAM4P,EAGA5P,GAGR,QAASmQ,GAAoB5R,EAAMgD,EAAMmO,GACxC,GAAMxU,EAAOyU,WAAYpR,GAAzB,CAIA,GAAIqC,GAAGkF,EAAG8J,EACTG,EAASxR,EAAKQ,SAGdiR,EAAQD,EAAS7U,EAAO8U,MAAQzR,EAChCgB,EAAKwQ,EAASxR,EAAMrD,EAAOkT,SAAYlT,EAAOkT,OAI/C,IAAM4B,EAAOzQ,GAAb,CAIA,GAAKgC,IAEJqO,EAAYF,EAAMM,EAAOzQ,GAAOyQ,EAAOzQ,GAAK+D,MAE3B,CAGVpI,EAAO0G,QAASL,GAsBrBA,EAAOA,EAAK9F,OAAQP,EAAO6F,IAAKQ,EAAMrG,EAAO8J,YAnBxCzD,IAAQqO,GACZrO,GAASA,IAITA,EAAOrG,EAAO8J,UAAWzD,GAExBA,EADIA,IAAQqO,IACHrO,GAEFA,EAAK4F,MAAM,KAarB,KAAMvG,EAAI,EAAGkF,EAAIvE,EAAK7C,OAAYoH,EAAJlF,EAAOA,UAC7BgP,GAAWrO,EAAKX,GAKxB,MAAQ8O,EAAMU,EAAoBlV,EAAOgI,eAAiB0M,GACzD,QAMGF,UACEM,GAAOzQ,GAAK+D,KAIb8M,EAAmBJ,EAAOzQ,QAM5BwQ,EACJ7U,EAAOmV,WAAa9R,IAAQ,GAGjBrD,EAAO6P,QAAQiC,eAAiBgD,GAASA,EAAMtV,aACnDsV,GAAOzQ,GAIdyQ,EAAOzQ,GAAO,QAIhBrE,EAAOiG,QACN6O,SAIA5B,QAAS,UAAa7S,EAAeoK,KAAK2K,UAAWrM,QAAS,MAAO,IAIrEsM,QACCC,OAAS,EAETlJ,OAAU,6CACVmJ,QAAU,GAGXC,QAAS,SAAUnS,GAElB,MADAA,GAAOA,EAAKQ,SAAW7D,EAAO8U,MAAOzR,EAAKrD,EAAOkT,UAAa7P,EAAMrD,EAAOkT,WAClE7P,IAAS6R,EAAmB7R,IAGtC+E,KAAM,SAAU/E,EAAMgD,EAAM+B,GAC3B,MAAOmM,GAAclR,EAAMgD,EAAM+B,IAGlCqN,WAAY,SAAUpS,EAAMgD,GAC3B,MAAO4O,GAAoB5R,EAAMgD,IAIlCqP,MAAO,SAAUrS,EAAMgD,EAAM+B,GAC5B,MAAOmM,GAAclR,EAAMgD,EAAM+B,GAAM,IAGxCuN,YAAa,SAAUtS,EAAMgD,GAC5B,MAAO4O,GAAoB5R,EAAMgD,GAAM,IAIxCoO,WAAY,SAAUpR,GAErB,GAAKA,EAAKQ,UAA8B,IAAlBR,EAAKQ,UAAoC,IAAlBR,EAAKQ,SACjD,OAAO,CAGR,IAAIwR,GAAShS,EAAK2G,UAAYhK,EAAOqV,OAAQhS,EAAK2G,SAASC,cAG3D,QAAQoL,GAAUA,KAAW,GAAQhS,EAAK4N,aAAa,aAAeoE,KAIxErV,EAAOsB,GAAG2E,QACTmC,KAAM,SAAUL,EAAKmC,GACpB,GAAI0L,GAAOvP,EACVhD,EAAOC,KAAK,GACZoC,EAAI,EACJ0C,EAAO,IAGR,IAAKL,IAAQtI,EAAY,CACxB,GAAK6D,KAAKE,SACT4E,EAAOpI,EAAOoI,KAAM/E,GAEG,IAAlBA,EAAKQ,WAAmB7D,EAAO0V,MAAOrS,EAAM,gBAAkB,CAElE,IADAuS,EAAQvS,EAAK4P,WACD2C,EAAMpS,OAAVkC,EAAkBA,IACzBW,EAAOuP,EAAMlQ,GAAGW,KAEVA,EAAKxF,QAAS,WACnBwF,EAAOrG,EAAO8J,UAAWzD,EAAK1F,MAAM,IAEpCkV,EAAUxS,EAAMgD,EAAM+B,EAAM/B,IAG9BrG,GAAO0V,MAAOrS,EAAM,eAAe,GAIrC,MAAO+E,GAIR,MAAoB,gBAARL,GACJzE,KAAK0B,KAAK,WAChBhF,EAAOoI,KAAM9E,KAAMyE,KAId/H,EAAOmL,OAAQ7H,KAAM,SAAU4G,GAErC,MAAKA,KAAUzK,EAEP4D,EAAOwS,EAAUxS,EAAM0E,EAAK/H,EAAOoI,KAAM/E,EAAM0E,IAAU,MAGjEzE,KAAK0B,KAAK,WACThF,EAAOoI,KAAM9E,KAAMyE,EAAKmC,KADzB5G,IAGE,KAAM4G,EAAO5E,UAAU9B,OAAS,EAAG,MAAM,IAG7CiS,WAAY,SAAU1N,GACrB,MAAOzE,MAAK0B,KAAK,WAChBhF,EAAOyV,WAAYnS,KAAMyE,OAK5B,SAAS8N,GAAUxS,EAAM0E,EAAKK,GAG7B,GAAKA,IAAS3I,GAA+B,IAAlB4D,EAAKQ,SAAiB,CAEhD,GAAIwC,GAAO,QAAU0B,EAAIgB,QAASuL,EAAY,OAAQrK,aAItD,IAFA7B,EAAO/E,EAAK4N,aAAc5K,GAEL,gBAAT+B,GAAoB,CAC/B,IACCA,EAAgB,SAATA,GAAkB,EACf,UAATA,GAAmB,EACV,SAATA,EAAkB,MAEjBA,EAAO,KAAOA,GAAQA,EACvBiM,EAAOtQ,KAAMqE,GAASpI,EAAO4I,UAAWR,GACvCA,EACD,MAAON,IAGT9H,EAAOoI,KAAM/E,EAAM0E,EAAKK,OAGxBA,GAAO3I,EAIT,MAAO2I,GAIR,QAAS8M,GAAmB5N,GAC3B,GAAIjB,EACJ,KAAMA,IAAQiB,GAGb,IAAc,SAATjB,IAAmBrG,EAAOgI,cAAeV,EAAIjB,MAGpC,WAATA,EACJ,OAAO,CAIT,QAAO,EAERrG,EAAOiG,QACN6P,MAAO,SAAUzS,EAAMV,EAAMyF,GAC5B,GAAI0N,EAEJ,OAAKzS,IACJV,GAASA,GAAQ,MAAS,QAC1BmT,EAAQ9V,EAAO0V,MAAOrS,EAAMV,GAGvByF,KACE0N,GAAS9V,EAAO0G,QAAQ0B,GAC7B0N,EAAQ9V,EAAO0V,MAAOrS,EAAMV,EAAM3C,EAAOsE,UAAU8D,IAEnD0N,EAAMrV,KAAM2H,IAGP0N,OAZR,GAgBDC,QAAS,SAAU1S,EAAMV,GACxBA,EAAOA,GAAQ,IAEf,IAAImT,GAAQ9V,EAAO8V,MAAOzS,EAAMV,GAC/BqT,EAAcF,EAAMtS,OACpBlC,EAAKwU,EAAM3I,QACX8I,EAAQjW,EAAOkW,YAAa7S,EAAMV,GAClCwT,EAAO,WACNnW,EAAO+V,QAAS1S,EAAMV,GAIZ,gBAAPrB,IACJA,EAAKwU,EAAM3I,QACX6I,KAGDC,EAAMG,IAAM9U,EACPA,IAIU,OAATqB,GACJmT,EAAMO,QAAS,oBAITJ,GAAMK,KACbhV,EAAGmD,KAAMpB,EAAM8S,EAAMF,KAGhBD,GAAeC,GACpBA,EAAMtI,MAAMV,QAKdiJ,YAAa,SAAU7S,EAAMV,GAC5B,GAAIoF,GAAMpF,EAAO,YACjB,OAAO3C,GAAO0V,MAAOrS,EAAM0E,IAAS/H,EAAO0V,MAAOrS,EAAM0E,GACvD4F,MAAO3N,EAAOuM,UAAU,eAAee,IAAI,WAC1CtN,EAAO2V,YAAatS,EAAMV,EAAO,SACjC3C,EAAO2V,YAAatS,EAAM0E,UAM9B/H,EAAOsB,GAAG2E,QACT6P,MAAO,SAAUnT,EAAMyF,GACtB,GAAImO,GAAS,CAQb,OANqB,gBAAT5T,KACXyF,EAAOzF,EACPA,EAAO,KACP4T,KAGuBA,EAAnBjR,UAAU9B,OACPxD,EAAO8V,MAAOxS,KAAK,GAAIX,GAGxByF,IAAS3I,EACf6D,KACAA,KAAK0B,KAAK,WACT,GAAI8Q,GAAQ9V,EAAO8V,MAAOxS,KAAMX,EAAMyF,EAGtCpI,GAAOkW,YAAa5S,KAAMX,GAEZ,OAATA,GAA8B,eAAbmT,EAAM,IAC3B9V,EAAO+V,QAASzS,KAAMX,MAI1BoT,QAAS,SAAUpT,GAClB,MAAOW,MAAK0B,KAAK,WAChBhF,EAAO+V,QAASzS,KAAMX,MAKxB6T,MAAO,SAAUC,EAAM9T,GAItB,MAHA8T,GAAOzW,EAAO0W,GAAK1W,EAAO0W,GAAGC,OAAQF,IAAUA,EAAOA,EACtD9T,EAAOA,GAAQ,KAERW,KAAKwS,MAAOnT,EAAM,SAAUwT,EAAMF,GACxC,GAAIW,GAAU1P,WAAYiP,EAAMM,EAChCR,GAAMK,KAAO,WACZO,aAAcD,OAIjBE,WAAY,SAAUnU,GACrB,MAAOW,MAAKwS,MAAOnT,GAAQ,UAI5BwC,QAAS,SAAUxC,EAAM2E,GACxB,GAAI6B,GACH4N,EAAQ,EACRC,EAAQhX,EAAO2L,WACfsL,EAAW3T,KACXoC,EAAIpC,KAAKE,OACToL,EAAU,aACCmI,GACTC,EAAM7P,YAAa8P,GAAYA,IAIb,iBAATtU,KACX2E,EAAM3E,EACNA,EAAOlD,GAERkD,EAAOA,GAAQ,IAEf,OAAO+C,IACNyD,EAAMnJ,EAAO0V,MAAOuB,EAAUvR,GAAK/C,EAAO,cACrCwG,GAAOA,EAAIwE,QACfoJ,IACA5N,EAAIwE,MAAML,IAAKsB,GAIjB,OADAA,KACOoI,EAAM7R,QAASmC,KAGxB,IAAI4P,GAAUC,EACbC,EAAS,YACTC,EAAU,MACVC,EAAa,6CACbC,EAAa,gBACbC,EAAW,8HACXC,EAAc,0BACd9G,EAAkB3Q,EAAO6P,QAAQc,gBACjC+G,EAAc1X,EAAO6P,QAAQE,KAE9B/P,GAAOsB,GAAG2E,QACT/B,KAAM,SAAUmC,EAAM6D,GACrB,MAAOlK,GAAOmL,OAAQ7H,KAAMtD,EAAOkE,KAAMmC,EAAM6D,EAAO5E,UAAU9B,OAAS,IAG1EmU,WAAY,SAAUtR,GACrB,MAAO/C,MAAK0B,KAAK,WAChBhF,EAAO2X,WAAYrU,KAAM+C,MAI3BuR,KAAM,SAAUvR,EAAM6D,GACrB,MAAOlK,GAAOmL,OAAQ7H,KAAMtD,EAAO4X,KAAMvR,EAAM6D,EAAO5E,UAAU9B,OAAS,IAG1EqU,WAAY,SAAUxR,GAErB,MADAA,GAAOrG,EAAO8X,QAASzR,IAAUA,EAC1B/C,KAAK0B,KAAK,WAEhB,IACC1B,KAAM+C,GAAS5G,QACR6D,MAAM+C,GACZ,MAAOyB,QAIXiQ,SAAU,SAAU7N,GACnB,GAAI8N,GAAS3U,EAAM+S,EAAK6B,EAAOrS,EAC9BF,EAAI,EACJC,EAAMrC,KAAKE,OACX0U,EAA2B,gBAAVhO,IAAsBA,CAExC,IAAKlK,EAAOiE,WAAYiG,GACvB,MAAO5G,MAAK0B,KAAK,SAAUY,GAC1B5F,EAAQsD,MAAOyU,SAAU7N,EAAMzF,KAAMnB,KAAMsC,EAAGtC,KAAKsN,aAIrD,IAAKsH,EAIJ,IAFAF,GAAY9N,GAAS,IAAK9G,MAAO1B,OAErBiE,EAAJD,EAASA,IAOhB,GANArC,EAAOC,KAAMoC,GACb0Q,EAAwB,IAAlB/S,EAAKQ,WAAoBR,EAAKuN,WACjC,IAAMvN,EAAKuN,UAAY,KAAM7H,QAASqO,EAAQ,KAChD,KAGU,CACVxR,EAAI,CACJ,OAASqS,EAAQD,EAAQpS,KACgB,EAAnCwQ,EAAIvV,QAAS,IAAMoX,EAAQ,OAC/B7B,GAAO6B,EAAQ,IAGjB5U,GAAKuN,UAAY5Q,EAAOmB,KAAMiV,GAMjC,MAAO9S,OAGR6U,YAAa,SAAUjO,GACtB,GAAI8N,GAAS3U,EAAM+S,EAAK6B,EAAOrS,EAC9BF,EAAI,EACJC,EAAMrC,KAAKE,OACX0U,EAA+B,IAArB5S,UAAU9B,QAAiC,gBAAV0G,IAAsBA,CAElE,IAAKlK,EAAOiE,WAAYiG,GACvB,MAAO5G,MAAK0B,KAAK,SAAUY,GAC1B5F,EAAQsD,MAAO6U,YAAajO,EAAMzF,KAAMnB,KAAMsC,EAAGtC,KAAKsN,aAGxD,IAAKsH,EAGJ,IAFAF,GAAY9N,GAAS,IAAK9G,MAAO1B,OAErBiE,EAAJD,EAASA,IAQhB,GAPArC,EAAOC,KAAMoC,GAEb0Q,EAAwB,IAAlB/S,EAAKQ,WAAoBR,EAAKuN,WACjC,IAAMvN,EAAKuN,UAAY,KAAM7H,QAASqO,EAAQ,KAChD,IAGU,CACVxR,EAAI,CACJ,OAASqS,EAAQD,EAAQpS,KAExB,MAAQwQ,EAAIvV,QAAS,IAAMoX,EAAQ,MAAS,EAC3C7B,EAAMA,EAAIrN,QAAS,IAAMkP,EAAQ,IAAK,IAGxC5U,GAAKuN,UAAY1G,EAAQlK,EAAOmB,KAAMiV,GAAQ,GAKjD,MAAO9S,OAGR8U,YAAa,SAAUlO,EAAOmO,GAC7B,GAAI1V,SAAcuH,GACjBoO,EAA6B,iBAAbD,EAEjB,OAAKrY,GAAOiE,WAAYiG,GAChB5G,KAAK0B,KAAK,SAAUU,GAC1B1F,EAAQsD,MAAO8U,YAAalO,EAAMzF,KAAKnB,KAAMoC,EAAGpC,KAAKsN,UAAWyH,GAAWA,KAItE/U,KAAK0B,KAAK,WAChB,GAAc,WAATrC,EAAoB,CAExB,GAAIiO,GACHlL,EAAI,EACJ0H,EAAOpN,EAAQsD,MACf4K,EAAQmK,EACRE,EAAarO,EAAM9G,MAAO1B,MAE3B,OAASkP,EAAY2H,EAAY7S,KAEhCwI,EAAQoK,EAASpK,GAASd,EAAKoL,SAAU5H,GACzCxD,EAAMc,EAAQ,WAAa,eAAiB0C,QAIlCjO,IAAS/C,GAA8B,YAAT+C,KACpCW,KAAKsN,WAET5Q,EAAO0V,MAAOpS,KAAM,gBAAiBA,KAAKsN,WAO3CtN,KAAKsN,UAAYtN,KAAKsN,WAAa1G,KAAU,EAAQ,GAAKlK,EAAO0V,MAAOpS,KAAM,kBAAqB,OAKtGkV,SAAU,SAAUpX,GACnB,GAAIwP,GAAY,IAAMxP,EAAW,IAChCsE,EAAI,EACJkF,EAAItH,KAAKE,MACV,MAAYoH,EAAJlF,EAAOA,IACd,GAA0B,IAArBpC,KAAKoC,GAAG7B,WAAmB,IAAMP,KAAKoC,GAAGkL,UAAY,KAAK7H,QAAQqO,EAAQ,KAAKvW,QAAS+P,IAAe,EAC3G,OAAO,CAIT,QAAO,GAGR6H,IAAK,SAAUvO,GACd,GAAIpF,GAAKmR,EAAOhS,EACfZ,EAAOC,KAAK,EAEb,EAAA,GAAMgC,UAAU9B,OAsBhB,MAFAS,GAAajE,EAAOiE,WAAYiG,GAEzB5G,KAAK0B,KAAK,SAAUU,GAC1B,GAAI+S,GACHrL,EAAOpN,EAAOsD,KAEQ,KAAlBA,KAAKO,WAKT4U,EADIxU,EACEiG,EAAMzF,KAAMnB,KAAMoC,EAAG0H,EAAKqL,OAE1BvO,EAIK,MAAPuO,EACJA,EAAM,GACoB,gBAARA,GAClBA,GAAO,GACIzY,EAAO0G,QAAS+R,KAC3BA,EAAMzY,EAAO6F,IAAI4S,EAAK,SAAWvO,GAChC,MAAgB,OAATA,EAAgB,GAAKA,EAAQ,MAItC+L,EAAQjW,EAAO0Y,SAAUpV,KAAKX,OAAU3C,EAAO0Y,SAAUpV,KAAK0G,SAASC,eAGjEgM,GAAW,OAASA,IAAUA,EAAM0C,IAAKrV,KAAMmV,EAAK,WAAchZ,IACvE6D,KAAK4G,MAAQuO,KAlDd,IAAKpV,EAGJ,MAFA4S,GAAQjW,EAAO0Y,SAAUrV,EAAKV,OAAU3C,EAAO0Y,SAAUrV,EAAK2G,SAASC,eAElEgM,GAAS,OAASA,KAAUnR,EAAMmR,EAAMvR,IAAKrB,EAAM,YAAe5D,EAC/DqF,GAGRA,EAAMzB,EAAK6G,MAEW,gBAARpF,GAEbA,EAAIiE,QAAQsO,EAAS,IAEd,MAAPvS,EAAc,GAAKA,OA2CxB9E,EAAOiG,QACNyS,UACCE,QACClU,IAAK,SAAUrB,GAGd,GAAIoV,GAAMpV,EAAK4P,WAAW/I,KAC1B,QAAQuO,GAAOA,EAAII,UAAYxV,EAAK6G,MAAQ7G,EAAK+G,OAGnD4F,QACCtL,IAAK,SAAUrB,GACd,GAAI6G,GAAO0O,EACVtS,EAAUjD,EAAKiD,QACfoH,EAAQrK,EAAKyV,cACbC,EAAoB,eAAd1V,EAAKV,MAAiC,EAAR+K,EACpC8B,EAASuJ,EAAM,QACfrO,EAAMqO,EAAMrL,EAAQ,EAAIpH,EAAQ9C,OAChCkC,EAAY,EAARgI,EACHhD,EACAqO,EAAMrL,EAAQ,CAGhB,MAAYhD,EAAJhF,EAASA,IAIhB,GAHAkT,EAAStS,EAASZ,MAGXkT,EAAOrH,UAAY7L,IAAMgI,IAE5B1N,EAAO6P,QAAQ0C,YAAeqG,EAAOhL,SAA+C,OAApCgL,EAAO3H,aAAa,cACnE2H,EAAOxU,WAAWwJ,UAAa5N,EAAOgK,SAAU4O,EAAOxU,WAAY,aAAiB,CAMxF,GAHA8F,EAAQlK,EAAQ4Y,GAASH,MAGpBM,EACJ,MAAO7O,EAIRsF,GAAO/O,KAAMyJ,GAIf,MAAOsF,IAGRmJ,IAAK,SAAUtV,EAAM6G,GACpB,GAAIsF,GAASxP,EAAOsE,UAAW4F,EAS/B,OAPAlK,GAAOqD,GAAMK,KAAK,UAAUsB,KAAK,WAChC1B,KAAKiO,SAAWvR,EAAOwK,QAASxK,EAAOsD,MAAMmV,MAAOjJ,IAAY,IAG3DA,EAAOhM,SACZH,EAAKyV,cAAgB,IAEftJ,KAKVtL,KAAM,SAAUb,EAAMgD,EAAM6D,GAC3B,GAAI+L,GAAO+C,EAAQlU,EAClBmU,EAAQ5V,EAAKQ,QAGd,IAAMR,GAAkB,IAAV4V,GAAyB,IAAVA,GAAyB,IAAVA,EAK5C,aAAY5V,GAAK4N,eAAiBrR,EAC1BI,EAAO4X,KAAMvU,EAAMgD,EAAM6D,IAGjC8O,EAAmB,IAAVC,IAAgBjZ,EAAOkZ,SAAU7V,GAIrC2V,IACJ3S,EAAOA,EAAK4D,cACZgM,EAAQjW,EAAOmZ,UAAW9S,KAAYmR,EAASzT,KAAMsC,GAAS8Q,EAAWD,IAGrEhN,IAAUzK,EAaHwW,GAAS+C,GAAU,OAAS/C,IAA6C,QAAnCnR,EAAMmR,EAAMvR,IAAKrB,EAAMgD,IACjEvB,SAMKzB,GAAK4N,eAAiBrR,IACjCkF,EAAOzB,EAAK4N,aAAc5K,IAIb,MAAPvB,EACNrF,EACAqF,GAzBc,OAAVoF,EAGO+L,GAAS+C,GAAU,OAAS/C,KAAUnR,EAAMmR,EAAM0C,IAAKtV,EAAM6G,EAAO7D,MAAY5G,EACpFqF,GAGPzB,EAAKiN,aAAcjK,EAAM6D,EAAQ,IAC1BA,IAPPlK,EAAO2X,WAAYtU,EAAMgD,GAAzBrG,KA4BH2X,WAAY,SAAUtU,EAAM6G,GAC3B,GAAI7D,GAAM+S,EACT1T,EAAI,EACJ2T,EAAYnP,GAASA,EAAM9G,MAAO1B,EAEnC,IAAK2X,GAA+B,IAAlBhW,EAAKQ,SACtB,MAASwC,EAAOgT,EAAU3T,KACzB0T,EAAWpZ,EAAO8X,QAASzR,IAAUA,EAGhCmR,EAASzT,KAAMsC,IAGbsK,GAAmB8G,EAAY1T,KAAMsC,GAC1ChD,EAAMrD,EAAO8J,UAAW,WAAazD,IACpChD,EAAM+V,IAAa,EAEpB/V,EAAM+V,IAAa,EAKpBpZ,EAAOkE,KAAMb,EAAMgD,EAAM,IAG1BhD,EAAKiW,gBAAiB3I,EAAkBtK,EAAO+S,IAKlDD,WACCxW,MACCgW,IAAK,SAAUtV,EAAM6G,GACpB,IAAMlK,EAAO6P,QAAQ2C,YAAwB,UAAVtI,GAAqBlK,EAAOgK,SAAS3G,EAAM,SAAW,CAGxF,GAAIoV,GAAMpV,EAAK6G,KAKf,OAJA7G,GAAKiN,aAAc,OAAQpG,GACtBuO,IACJpV,EAAK6G,MAAQuO,GAEPvO,MAMX4N,SACCyB,SAAU,WACVC,SAAU,WACVC,MAAO,UACPC,QAAS,YACTC,UAAW,YACXC,YAAa,cACbC,YAAa,cACbC,QAAS,UACTC,QAAS,UACTC,OAAQ,SACRC,YAAa,cACbC,gBAAiB,mBAGlBtC,KAAM,SAAUvU,EAAMgD,EAAM6D,GAC3B,GAAIpF,GAAKmR,EAAO+C,EACfC,EAAQ5V,EAAKQ,QAGd,IAAMR,GAAkB,IAAV4V,GAAyB,IAAVA,GAAyB,IAAVA,EAY5C,MARAD,GAAmB,IAAVC,IAAgBjZ,EAAOkZ,SAAU7V,GAErC2V,IAEJ3S,EAAOrG,EAAO8X,QAASzR,IAAUA,EACjC4P,EAAQjW,EAAOma,UAAW9T,IAGtB6D,IAAUzK,EACTwW,GAAS,OAASA,KAAUnR,EAAMmR,EAAM0C,IAAKtV,EAAM6G,EAAO7D,MAAY5G,EACnEqF,EAGEzB,EAAMgD,GAAS6D,EAIpB+L,GAAS,OAASA,IAA6C,QAAnCnR,EAAMmR,EAAMvR,IAAKrB,EAAMgD,IAChDvB,EAGAzB,EAAMgD,IAKhB8T,WACCC,UACC1V,IAAK,SAAUrB,GAGd,GAAIgX,GAAgBhX,EAAKiX,iBAAiB,WAE1C,OAAOD,IAAiBA,EAAcxB,UACrC0B,SAAUF,EAAcnQ,MAAO,IAC/BoN,EAAWvT,KAAMV,EAAK2G,WAAcuN,EAAWxT,KAAMV,EAAK2G,WAAc3G,EAAKmX,KAC5E,EACA/a,OAON0X,GACCzS,IAAK,SAAUrB,EAAMgD,GACpB,GAECuR,GAAO5X,EAAO4X,KAAMvU,EAAMgD,GAG1BnC,EAAuB,iBAAT0T,IAAsBvU,EAAK4N,aAAc5K,GACvDoU,EAAyB,iBAAT7C,GAEfF,GAAe/G,EACN,MAARzM,EAGAuT,EAAY1T,KAAMsC,GACjBhD,EAAMrD,EAAO8J,UAAW,WAAazD,MACnCnC,EAGJb,EAAKiX,iBAAkBjU,EAEzB,OAAOoU,IAAUA,EAAOvQ,SAAU,EACjC7D,EAAK4D,cACLxK,GAEFkZ,IAAK,SAAUtV,EAAM6G,EAAO7D,GAa3B,MAZK6D,MAAU,EAEdlK,EAAO2X,WAAYtU,EAAMgD,GACdqR,GAAe/G,IAAoB8G,EAAY1T,KAAMsC,GAEhEhD,EAAKiN,cAAeK,GAAmB3Q,EAAO8X,QAASzR,IAAUA,EAAMA,GAIvEhD,EAAMrD,EAAO8J,UAAW,WAAazD,IAAWhD,EAAMgD,IAAS,EAGzDA,IAKHqR,GAAgB/G,IACrB3Q,EAAOmZ,UAAUjP,OAChBxF,IAAK,SAAUrB,EAAMgD,GACpB,GAAIvB,GAAMzB,EAAKiX,iBAAkBjU,EACjC,OAAOrG,GAAOgK,SAAU3G,EAAM,SAG7BA,EAAKqX,aAEL5V,GAAOA,EAAI+T,UAAY/T,EAAIoF,MAAQzK,GAErCkZ,IAAK,SAAUtV,EAAM6G,EAAO7D,GAC3B,MAAKrG,GAAOgK,SAAU3G,EAAM,UAE3BA,EAAKqX,aAAexQ,EAApB7G,GAGO6T,GAAYA,EAASyB,IAAKtV,EAAM6G,EAAO7D,MAO5CsK,IAILuG,EAAWlX,EAAO0Y,SAASiC,QAC1BjW,IAAK,SAAUrB,EAAMgD,GACpB,GAAIvB,GAAMzB,EAAKiX,iBAAkBjU,EACjC,OAAOvB,KAAkB,OAATuB,GAA0B,SAATA,GAA4B,WAATA,EAAkC,KAAdvB,EAAIoF,MAAepF,EAAI+T,WAC9F/T,EAAIoF,MACJzK,GAEFkZ,IAAK,SAAUtV,EAAM6G,EAAO7D,GAE3B,GAAIvB,GAAMzB,EAAKiX,iBAAkBjU,EAUjC,OATMvB,IACLzB,EAAKuX,iBACH9V,EAAMzB,EAAKS,cAAc+W,gBAAiBxU,IAI7CvB,EAAIoF,MAAQA,GAAS,GAGL,UAAT7D,GAAoB6D,IAAU7G,EAAK4N,aAAc5K,GACvD6D,EACAzK,IAMHO,EAAOmZ,UAAUe,iBAChBxV,IAAKwS,EAASxS,IACdiU,IAAK,SAAUtV,EAAM6G,EAAO7D,GAC3B6Q,EAASyB,IAAKtV,EAAgB,KAAV6G,GAAe,EAAQA,EAAO7D,KAMpDrG,EAAOgF,MAAO,QAAS,UAAY,SAAUU,EAAGW,GAC/CrG,EAAOmZ,UAAW9S,GAASrG,EAAOiG,OAAQjG,EAAOmZ,UAAW9S,IAC3DsS,IAAK,SAAUtV,EAAM6G,GACpB,MAAe,KAAVA,GACJ7G,EAAKiN,aAAcjK,EAAM,QAClB6D,GAFR,QAYElK,EAAO6P,QAAQqB,iBACpBlR,EAAOgF,MAAO,OAAQ,MAAO,QAAS,UAAY,SAAUU,EAAGW,GAC9DrG,EAAOmZ,UAAW9S,GAASrG,EAAOiG,OAAQjG,EAAOmZ,UAAW9S,IAC3D3B,IAAK,SAAUrB,GACd,GAAIyB,GAAMzB,EAAK4N,aAAc5K,EAAM,EACnC,OAAc,OAAPvB,EAAcrF,EAAYqF,OAMpC9E,EAAOgF,MAAO,OAAQ,OAAS,SAAUU,EAAGW,GAC3CrG,EAAOma,UAAW9T,IACjB3B,IAAK,SAAUrB,GACd,MAAOA,GAAK4N,aAAc5K,EAAM,QAM9BrG,EAAO6P,QAAQY,QACpBzQ,EAAOmZ,UAAU1I,OAChB/L,IAAK,SAAUrB,GAId,MAAOA,GAAKoN,MAAMC,SAAWjR,GAE9BkZ,IAAK,SAAUtV,EAAM6G,GACpB,MAAS7G,GAAKoN,MAAMC,QAAUxG,EAAQ,MAOnClK,EAAO6P,QAAQyB,cACpBtR,EAAOma,UAAU5I,SAAWvR,EAAOiG,OAAQjG,EAAOma,UAAU5I,UAC3D7M,IAAK,SAAUrB,GACd,GAAIyX,GAASzX,EAAKe,UAUlB,OARK0W,KACJA,EAAOhC,cAGFgC,EAAO1W,YACX0W,EAAO1W,WAAW0U,eAGb,SAMJ9Y,EAAO6P,QAAQ2B,UACpBxR,EAAO8X,QAAQtG,QAAU,YAIpBxR,EAAO6P,QAAQwB,SACpBrR,EAAOgF,MAAO,QAAS,YAAc,WACpChF,EAAO0Y,SAAUpV,OAChBoB,IAAK,SAAUrB,GAEd,MAAsC,QAA/BA,EAAK4N,aAAa,SAAoB,KAAO5N,EAAK6G,UAK7DlK,EAAOgF,MAAO,QAAS,YAAc,WACpChF,EAAO0Y,SAAUpV,MAAStD,EAAOiG,OAAQjG,EAAO0Y,SAAUpV,OACzDqV,IAAK,SAAUtV,EAAM6G,GACpB,MAAKlK,GAAO0G,QAASwD,GACX7G,EAAKgP,QAAUrS,EAAOwK,QAASxK,EAAOqD,GAAMoV,MAAOvO,IAAW,EADxE,MAMH,IAAI6Q,GAAa,+BAChBC,GAAY,OACZC,GAAc,+BACdC,GAAc,kCACdC,GAAiB,sBAElB,SAASC,MACR,OAAO,EAGR,QAASC,MACR,OAAO,EAORrb,EAAOyC,OAEN6Y,UAEAhO,IAAK,SAAUjK,EAAMkY,EAAOC,EAASpT,EAAMhH,GAC1C,GAAI+H,GAAKsS,EAAQC,EAAGC,EACnBC,EAASC,EAAaC,EACtBC,EAAUpZ,EAAMqZ,EAAYC,EAC5BC,EAAWlc,EAAO0V,MAAOrS,EAG1B,IAAM6Y,EAAN,CAKKV,EAAQA,UACZG,EAAcH,EACdA,EAAUG,EAAYH,QACtBpa,EAAWua,EAAYva,UAIlBoa,EAAQvQ,OACbuQ,EAAQvQ,KAAOjL,EAAOiL,SAIhBwQ,EAASS,EAAST,UACxBA,EAASS,EAAST,YAEZI,EAAcK,EAASC,UAC7BN,EAAcK,EAASC,OAAS,SAAUrU,GAGzC,aAAc9H,KAAWJ,GAAuBkI,GAAK9H,EAAOyC,MAAM2Z,YAActU,EAAEnF,KAEjFlD,EADAO,EAAOyC,MAAM4Z,SAAShX,MAAOwW,EAAYxY,KAAMiC,YAIjDuW,EAAYxY,KAAOA,GAKpBkY,GAAUA,GAAS,IAAKnY,MAAO1B,KAAqB,IACpDga,EAAIH,EAAM/X,MACV,OAAQkY,IACPvS,EAAMgS,GAAe1X,KAAM8X,EAAMG,QACjC/Y,EAAOsZ,EAAW9S,EAAI,GACtB6S,GAAe7S,EAAI,IAAM,IAAK8C,MAAO,KAAMlG,OAG3C6V,EAAU5b,EAAOyC,MAAMmZ,QAASjZ,OAGhCA,GAASvB,EAAWwa,EAAQU,aAAeV,EAAQW,WAAc5Z,EAGjEiZ,EAAU5b,EAAOyC,MAAMmZ,QAASjZ,OAGhCmZ,EAAY9b,EAAOiG,QAClBtD,KAAMA,EACNsZ,SAAUA,EACV7T,KAAMA,EACNoT,QAASA,EACTvQ,KAAMuQ,EAAQvQ,KACd7J,SAAUA,EACVob,aAAcpb,GAAYpB,EAAOyc,KAAKrZ,MAAMoZ,aAAazY,KAAM3C,GAC/Dsb,UAAWV,EAAWW,KAAK,MACzBhB,IAGII,EAAWN,EAAQ9Y,MACzBoZ,EAAWN,EAAQ9Y,MACnBoZ,EAASa,cAAgB,EAGnBhB,EAAQiB,OAASjB,EAAQiB,MAAMpY,KAAMpB,EAAM+E,EAAM4T,EAAYH,MAAkB,IAE/ExY,EAAKX,iBACTW,EAAKX,iBAAkBC,EAAMkZ,GAAa,GAE/BxY,EAAKuI,aAChBvI,EAAKuI,YAAa,KAAOjJ,EAAMkZ,KAK7BD,EAAQtO,MACZsO,EAAQtO,IAAI7I,KAAMpB,EAAMyY,GAElBA,EAAUN,QAAQvQ,OACvB6Q,EAAUN,QAAQvQ,KAAOuQ,EAAQvQ,OAK9B7J,EACJ2a,EAAS/V,OAAQ+V,EAASa,gBAAiB,EAAGd,GAE9CC,EAAStb,KAAMqb,GAIhB9b,EAAOyC,MAAM6Y,OAAQ3Y,IAAS,CAI/BU,GAAO,OAIRqF,OAAQ,SAAUrF,EAAMkY,EAAOC,EAASpa,EAAU0b,GACjD,GAAIlX,GAAGkW,EAAW3S,EACjB4T,EAAWrB,EAAGD,EACdG,EAASG,EAAUpZ,EACnBqZ,EAAYC,EACZC,EAAWlc,EAAOwV,QAASnS,IAAUrD,EAAO0V,MAAOrS,EAEpD,IAAM6Y,IAAcT,EAASS,EAAST,QAAtC,CAKAF,GAAUA,GAAS,IAAKnY,MAAO1B,KAAqB,IACpDga,EAAIH,EAAM/X,MACV,OAAQkY,IAMP,GALAvS,EAAMgS,GAAe1X,KAAM8X,EAAMG,QACjC/Y,EAAOsZ,EAAW9S,EAAI,GACtB6S,GAAe7S,EAAI,IAAM,IAAK8C,MAAO,KAAMlG,OAGrCpD,EAAN,CAOAiZ,EAAU5b,EAAOyC,MAAMmZ,QAASjZ,OAChCA,GAASvB,EAAWwa,EAAQU,aAAeV,EAAQW,WAAc5Z,EACjEoZ,EAAWN,EAAQ9Y,OACnBwG,EAAMA,EAAI,IAAU6T,OAAQ,UAAYhB,EAAWW,KAAK,iBAAmB,WAG3EI,EAAYnX,EAAImW,EAASvY,MACzB,OAAQoC,IACPkW,EAAYC,EAAUnW,IAEfkX,GAAeb,IAAaH,EAAUG,UACzCT,GAAWA,EAAQvQ,OAAS6Q,EAAU7Q,MACtC9B,IAAOA,EAAIpF,KAAM+X,EAAUY,YAC3Btb,GAAYA,IAAa0a,EAAU1a,WAAyB,OAAbA,IAAqB0a,EAAU1a,YACjF2a,EAAS/V,OAAQJ,EAAG,GAEfkW,EAAU1a,UACd2a,EAASa,gBAELhB,EAAQlT,QACZkT,EAAQlT,OAAOjE,KAAMpB,EAAMyY,GAOzBiB,KAAchB,EAASvY,SACrBoY,EAAQqB,UAAYrB,EAAQqB,SAASxY,KAAMpB,EAAM2Y,EAAYE,EAASC,WAAa,GACxFnc,EAAOkd,YAAa7Z,EAAMV,EAAMuZ,EAASC,cAGnCV,GAAQ9Y,QAtCf,KAAMA,IAAQ8Y,GACbzb,EAAOyC,MAAMiG,OAAQrF,EAAMV,EAAO4Y,EAAOG,GAAKF,EAASpa,GAAU,EA0C/DpB,GAAOgI,cAAeyT,WACnBS,GAASC,OAIhBnc,EAAO2V,YAAatS,EAAM,aAI5B+D,QAAS,SAAU3E,EAAO2F,EAAM/E,EAAM8Z,GACrC,GAAIhB,GAAQiB,EAAQhH,EACnBiH,EAAYzB,EAASzS,EAAKzD,EAC1B4X,GAAcja,GAAQxD,GACtB8C,EAAO3B,EAAYyD,KAAMhC,EAAO,QAAWA,EAAME,KAAOF,EACxDuZ,EAAahb,EAAYyD,KAAMhC,EAAO,aAAgBA,EAAMia,UAAUzQ,MAAM,OAK7E,IAHAmK,EAAMjN,EAAM9F,EAAOA,GAAQxD,EAGJ,IAAlBwD,EAAKQ,UAAoC,IAAlBR,EAAKQ,WAK5BqX,GAAYnX,KAAMpB,EAAO3C,EAAOyC,MAAM2Z,aAItCzZ,EAAK9B,QAAQ,MAAQ,IAEzBmb,EAAarZ,EAAKsJ,MAAM,KACxBtJ,EAAOqZ,EAAW7O,QAClB6O,EAAWjW,QAEZqX,EAA6B,EAApBza,EAAK9B,QAAQ,MAAY,KAAO8B,EAGzCF,EAAQA,EAAOzC,EAAOkT,SACrBzQ,EACA,GAAIzC,GAAOud,MAAO5a,EAAuB,gBAAVF,IAAsBA,GAEtDA,EAAM+a,WAAY,EAClB/a,EAAMia,UAAYV,EAAWW,KAAK,KAClCla,EAAMgb,aAAehb,EAAMia,UACtBM,OAAQ,UAAYhB,EAAWW,KAAK,iBAAmB,WAC3D,KAGDla,EAAMib,OAASje,EACTgD,EAAM+D,SACX/D,EAAM+D,OAASnD,GAIhB+E,EAAe,MAARA,GACJ3F,GACFzC,EAAOsE,UAAW8D,GAAQ3F,IAG3BmZ,EAAU5b,EAAOyC,MAAMmZ,QAASjZ,OAC1Bwa,IAAgBvB,EAAQxU,SAAWwU,EAAQxU,QAAQ/B,MAAOhC,EAAM+E,MAAW,GAAjF,CAMA,IAAM+U,IAAiBvB,EAAQ+B,WAAa3d,EAAOwH,SAAUnE,GAAS,CAMrE,IAJAga,EAAazB,EAAQU,cAAgB3Z,EAC/BuY,GAAYnX,KAAMsZ,EAAa1a,KACpCyT,EAAMA,EAAIhS,YAEHgS,EAAKA,EAAMA,EAAIhS,WACtBkZ,EAAU7c,KAAM2V,GAChBjN,EAAMiN,CAIFjN,MAAS9F,EAAKS,eAAiBjE,IACnCyd,EAAU7c,KAAM0I,EAAIyU,aAAezU,EAAI0U,cAAgBre,GAKzDkG,EAAI,CACJ,QAAS0Q,EAAMkH,EAAU5X,QAAUjD,EAAMqb,uBAExCrb,EAAME,KAAO+C,EAAI,EAChB2X,EACAzB,EAAQW,UAAY5Z,EAGrBwZ,GAAWnc,EAAO0V,MAAOU,EAAK,eAAoB3T,EAAME,OAAU3C,EAAO0V,MAAOU,EAAK,UAChF+F,GACJA,EAAO9W,MAAO+Q,EAAKhO,GAIpB+T,EAASiB,GAAUhH,EAAKgH,GACnBjB,GAAUnc,EAAOyU,WAAY2B,IAAS+F,EAAO9W,OAAS8W,EAAO9W,MAAO+Q,EAAKhO,MAAW,GACxF3F,EAAMsb,gBAMR,IAHAtb,EAAME,KAAOA,IAGPwa,GAAiB1a,EAAMub,sBAErBpC,EAAQqC,UAAYrC,EAAQqC,SAAS5Y,MAAOhC,EAAKS,cAAesE,MAAW,GACtE,UAATzF,GAAoB3C,EAAOgK,SAAU3G,EAAM,OAAUrD,EAAOyU,WAAYpR,KAKrE+Z,IAAU/Z,EAAMV,IAAW3C,EAAOwH,SAAUnE,IAAS,CAGzD8F,EAAM9F,EAAM+Z,GAEPjU,IACJ9F,EAAM+Z,GAAW,MAIlBpd,EAAOyC,MAAM2Z,UAAYzZ,CACzB,KACCU,EAAMV,KACL,MAAQmF,IAIV9H,EAAOyC,MAAM2Z,UAAY3c,EAEpB0J,IACJ9F,EAAM+Z,GAAWjU,GAMrB,MAAO1G,GAAMib,SAGdrB,SAAU,SAAU5Z,GAGnBA,EAAQzC,EAAOyC,MAAMyb,IAAKzb,EAE1B,IAAIiD,GAAGZ,EAAKgX,EAAWqC,EAASvY,EAC/BwY,KACAlZ,EAAOxE,EAAW+D,KAAMa,WACxByW,GAAa/b,EAAO0V,MAAOpS,KAAM,eAAoBb,EAAME,UAC3DiZ,EAAU5b,EAAOyC,MAAMmZ,QAASnZ,EAAME,SAOvC,IAJAuC,EAAK,GAAKzC,EACVA,EAAM4b,eAAiB/a,MAGlBsY,EAAQ0C,aAAe1C,EAAQ0C,YAAY7Z,KAAMnB,KAAMb,MAAY,EAAxE,CAKA2b,EAAepe,EAAOyC,MAAMsZ,SAAStX,KAAMnB,KAAMb,EAAOsZ,GAGxDrW,EAAI,CACJ,QAASyY,EAAUC,EAAc1Y,QAAWjD,EAAMqb,uBAAyB,CAC1Erb,EAAM8b,cAAgBJ,EAAQ9a,KAE9BuC,EAAI,CACJ,QAASkW,EAAYqC,EAAQpC,SAAUnW,QAAWnD,EAAM+b,kCAIjD/b,EAAMgb,cAAgBhb,EAAMgb,aAAa1Z,KAAM+X,EAAUY,cAE9Dja,EAAMqZ,UAAYA,EAClBrZ,EAAM2F,KAAO0T,EAAU1T,KAEvBtD,IAAS9E,EAAOyC,MAAMmZ,QAASE,EAAUG,eAAkBE,QAAUL,EAAUN,SAC5EnW,MAAO8Y,EAAQ9a,KAAM6B,GAEnBJ,IAAQrF,IACNgD,EAAMib,OAAS5Y,MAAS,IAC7BrC,EAAMsb,iBACNtb,EAAMgc,oBAYX,MAJK7C,GAAQ8C,cACZ9C,EAAQ8C,aAAaja,KAAMnB,KAAMb,GAG3BA,EAAMib,SAGd3B,SAAU,SAAUtZ,EAAOsZ,GAC1B,GAAI4C,GAAK7C,EAAW8C,EAASlZ,EAC5B0Y,KACAxB,EAAgBb,EAASa,cACzBxG,EAAM3T,EAAM+D,MAKb,IAAKoW,GAAiBxG,EAAIvS,YAAcpB,EAAMkY,QAAyB,UAAflY,EAAME,MAE7D,KAAQyT,GAAO9S,KAAM8S,EAAMA,EAAIhS,YAAcd,KAI5C,GAAsB,IAAjB8S,EAAIvS,WAAmBuS,EAAIxI,YAAa,GAAuB,UAAfnL,EAAME,MAAoB,CAE9E,IADAic,KACMlZ,EAAI,EAAOkX,EAAJlX,EAAmBA,IAC/BoW,EAAYC,EAAUrW,GAGtBiZ,EAAM7C,EAAU1a,SAAW,IAEtBwd,EAASD,KAAUlf,IACvBmf,EAASD,GAAQ7C,EAAUU,aAC1Bxc,EAAQ2e,EAAKrb,MAAOoK,MAAO0I,IAAS,EACpCpW,EAAO0D,KAAMib,EAAKrb,KAAM,MAAQ8S,IAAQ5S,QAErCob,EAASD,IACbC,EAAQne,KAAMqb,EAGX8C,GAAQpb,QACZ4a,EAAa3d,MAAO4C,KAAM+S,EAAK2F,SAAU6C,IAW7C,MAJqB7C,GAASvY,OAAzBoZ,GACJwB,EAAa3d,MAAO4C,KAAMC,KAAMyY,SAAUA,EAASpb,MAAOic,KAGpDwB,GAGRF,IAAK,SAAUzb,GACd,GAAKA,EAAOzC,EAAOkT,SAClB,MAAOzQ,EAIR,IAAIiD,GAAGkS,EAAMxR,EACZzD,EAAOF,EAAME,KACbkc,EAAgBpc,EAChBqc,EAAUxb,KAAKyb,SAAUpc,EAEpBmc,KACLxb,KAAKyb,SAAUpc,GAASmc,EACvB7D,GAAYlX,KAAMpB,GAASW,KAAK0b,WAChChE,GAAUjX,KAAMpB,GAASW,KAAK2b,aAGhC7Y,EAAO0Y,EAAQI,MAAQ5b,KAAK4b,MAAM3e,OAAQue,EAAQI,OAAU5b,KAAK4b,MAEjEzc,EAAQ,GAAIzC,GAAOud,MAAOsB,GAE1BnZ,EAAIU,EAAK5C,MACT,OAAQkC,IACPkS,EAAOxR,EAAMV,GACbjD,EAAOmV,GAASiH,EAAejH,EAmBhC,OAdMnV,GAAM+D,SACX/D,EAAM+D,OAASqY,EAAcM,YAActf,GAKb,IAA1B4C,EAAM+D,OAAO3C,WACjBpB,EAAM+D,OAAS/D,EAAM+D,OAAOpC,YAK7B3B,EAAM2c,UAAY3c,EAAM2c,QAEjBN,EAAQO,OAASP,EAAQO,OAAQ5c,EAAOoc,GAAkBpc,GAIlEyc,MAAO,wHAAwHjT,MAAM,KAErI8S,YAEAE,UACCC,MAAO,4BAA4BjT,MAAM,KACzCoT,OAAQ,SAAU5c,EAAO6c,GAOxB,MAJoB,OAAf7c,EAAM8c,QACV9c,EAAM8c,MAA6B,MAArBD,EAASE,SAAmBF,EAASE,SAAWF,EAASG,SAGjEhd,IAITuc,YACCE,MAAO,mGAAmGjT,MAAM,KAChHoT,OAAQ,SAAU5c,EAAO6c,GACxB,GAAIrY,GAAMyY,EAAUC,EACnBhF,EAAS2E,EAAS3E,OAClBiF,EAAcN,EAASM,WAuBxB,OApBoB,OAAfnd,EAAMod,OAAqC,MAApBP,EAASQ,UACpCJ,EAAWjd,EAAM+D,OAAO1C,eAAiBjE,EACzC8f,EAAMD,EAASjW,gBACfxC,EAAOyY,EAASzY,KAEhBxE,EAAMod,MAAQP,EAASQ,SAAYH,GAAOA,EAAII,YAAc9Y,GAAQA,EAAK8Y,YAAc,IAAQJ,GAAOA,EAAIK,YAAc/Y,GAAQA,EAAK+Y,YAAc,GACnJvd,EAAMwd,MAAQX,EAASY,SAAYP,GAAOA,EAAIQ,WAAclZ,GAAQA,EAAKkZ,WAAc,IAAQR,GAAOA,EAAIS,WAAcnZ,GAAQA,EAAKmZ,WAAc,KAI9I3d,EAAM4d,eAAiBT,IAC5Bnd,EAAM4d,cAAgBT,IAAgBnd,EAAM+D,OAAS8Y,EAASgB,UAAYV,GAKrEnd,EAAM8c,OAAS5E,IAAWlb,IAC/BgD,EAAM8c,MAAmB,EAAT5E,EAAa,EAAe,EAATA,EAAa,EAAe,EAATA,EAAa,EAAI,GAGjElY,IAITmZ,SACC2E,MAEC5C,UAAU,GAEX9K,OAECzL,QAAS,WACR,MAAKpH,GAAOgK,SAAU1G,KAAM,UAA2B,aAAdA,KAAKX,MAAuBW,KAAKuP,OACzEvP,KAAKuP,SACE,GAFR,IAMF2N,OAECpZ,QAAS,WACR,GAAK9D,OAASzD,EAAS4gB,eAAiBnd,KAAKkd,MAC5C,IAEC,MADAld,MAAKkd,SACE,EACN,MAAQ1Y,MAOZwU,aAAc,WAEfoE,MACCtZ,QAAS,WACR,MAAK9D,QAASzD,EAAS4gB,eAAiBnd,KAAKod,MAC5Cpd,KAAKod,QACE,GAFR,GAKDpE,aAAc,YAGfqE,cACCjC,aAAc,SAAUjc,GAGlBA,EAAMib,SAAWje,IACrBgD,EAAMoc,cAAc+B,YAAcne,EAAMib,WAM5CmD,SAAU,SAAUle,EAAMU,EAAMZ,EAAOqe,GAItC,GAAIhZ,GAAI9H,EAAOiG,OACd,GAAIjG,GAAOud,MACX9a,GACEE,KAAMA,EACPoe,aAAa,EACblC,kBAGGiC,GACJ9gB,EAAOyC,MAAM2E,QAASU,EAAG,KAAMzE,GAE/BrD,EAAOyC,MAAM4Z,SAAS5X,KAAMpB,EAAMyE,GAE9BA,EAAEkW,sBACNvb,EAAMsb,mBAKT/d,EAAOkd,YAAcrd,EAASkD,oBAC7B,SAAUM,EAAMV,EAAMwZ,GAChB9Y,EAAKN,qBACTM,EAAKN,oBAAqBJ,EAAMwZ,GAAQ,IAG1C,SAAU9Y,EAAMV,EAAMwZ,GACrB,GAAI9V,GAAO,KAAO1D,CAEbU,GAAKL,oBAIGK,GAAMgD,KAAWzG,IAC5ByD,EAAMgD,GAAS,MAGhBhD,EAAKL,YAAaqD,EAAM8V,KAI3Bnc,EAAOud,MAAQ,SAAUrX,EAAKgZ,GAE7B,MAAO5b,gBAAgBtD,GAAOud,OAKzBrX,GAAOA,EAAIvD,MACfW,KAAKub,cAAgB3Y,EACrB5C,KAAKX,KAAOuD,EAAIvD,KAIhBW,KAAK0a,mBAAuB9X,EAAI8a,kBAAoB9a,EAAI0a,eAAgB,GACvE1a,EAAI+a,mBAAqB/a,EAAI+a,oBAAwB7F,GAAaC,IAInE/X,KAAKX,KAAOuD,EAIRgZ,GACJlf,EAAOiG,OAAQ3C,KAAM4b,GAItB5b,KAAK4d,UAAYhb,GAAOA,EAAIgb,WAAalhB,EAAOwL,MAGhDlI,KAAMtD,EAAOkT,UAAY,EAvBzB,GAJQ,GAAIlT,GAAOud,MAAOrX,EAAKgZ,IAgChClf,EAAOud,MAAMta,WACZ+a,mBAAoB3C,GACpByC,qBAAsBzC,GACtBmD,8BAA+BnD,GAE/B0C,eAAgB,WACf,GAAIjW,GAAIxE,KAAKub,aAEbvb,MAAK0a,mBAAqB5C,GACpBtT,IAKDA,EAAEiW,eACNjW,EAAEiW,iBAKFjW,EAAE8Y,aAAc,IAGlBnC,gBAAiB,WAChB,GAAI3W,GAAIxE,KAAKub,aAEbvb,MAAKwa,qBAAuB1C,GACtBtT,IAIDA,EAAE2W,iBACN3W,EAAE2W,kBAKH3W,EAAEqZ,cAAe,IAElBC,yBAA0B,WACzB9d,KAAKkb,8BAAgCpD,GACrC9X,KAAKmb,oBAKPze,EAAOgF,MACNqc,WAAY,YACZC,WAAY,YACV,SAAUC,EAAMrD,GAClBle,EAAOyC,MAAMmZ,QAAS2F,IACrBjF,aAAc4B,EACd3B,SAAU2B,EAEV/B,OAAQ,SAAU1Z,GACjB,GAAIqC,GACH0B,EAASlD,KACTke,EAAU/e,EAAM4d,cAChBvE,EAAYrZ,EAAMqZ,SASnB;QALM0F,GAAYA,IAAYhb,IAAWxG,EAAOyhB,SAAUjb,EAAQgb,MACjE/e,EAAME,KAAOmZ,EAAUG,SACvBnX,EAAMgX,EAAUN,QAAQnW,MAAO/B,KAAMgC,WACrC7C,EAAME,KAAOub,GAEPpZ,MAMJ9E,EAAO6P,QAAQ6R,gBAEpB1hB,EAAOyC,MAAMmZ,QAAQ9I,QACpB+J,MAAO,WAEN,MAAK7c,GAAOgK,SAAU1G,KAAM,SACpB,GAIRtD,EAAOyC,MAAM6K,IAAKhK,KAAM,iCAAkC,SAAUwE,GAEnE,GAAIzE,GAAOyE,EAAEtB,OACZmb,EAAO3hB,EAAOgK,SAAU3G,EAAM,UAAarD,EAAOgK,SAAU3G,EAAM,UAAaA,EAAKse,KAAOliB,CACvFkiB,KAAS3hB,EAAO0V,MAAOiM,EAAM,mBACjC3hB,EAAOyC,MAAM6K,IAAKqU,EAAM,iBAAkB,SAAUlf,GACnDA,EAAMmf,gBAAiB,IAExB5hB,EAAO0V,MAAOiM,EAAM,iBAAiB,MARvC3hB,IAcD0e,aAAc,SAAUjc,GAElBA,EAAMmf,uBACHnf,GAAMmf,eACRte,KAAKc,aAAe3B,EAAM+a,WAC9Bxd,EAAOyC,MAAMoe,SAAU,SAAUvd,KAAKc,WAAY3B,GAAO,KAK5Dwa,SAAU,WAET,MAAKjd,GAAOgK,SAAU1G,KAAM,SACpB,GAIRtD,EAAOyC,MAAMiG,OAAQpF,KAAM,YAA3BtD,MAMGA,EAAO6P,QAAQgS,gBAEpB7hB,EAAOyC,MAAMmZ,QAAQ7I,QAEpB8J,MAAO,WAEN,MAAK9B,GAAWhX,KAAMT,KAAK0G,YAIP,aAAd1G,KAAKX,MAAqC,UAAdW,KAAKX,QACrC3C,EAAOyC,MAAM6K,IAAKhK,KAAM,yBAA0B,SAAUb,GACjB,YAArCA,EAAMoc,cAAciD,eACxBxe,KAAKye,eAAgB,KAGvB/hB,EAAOyC,MAAM6K,IAAKhK,KAAM,gBAAiB,SAAUb,GAC7Ca,KAAKye,gBAAkBtf,EAAM+a,YACjCla,KAAKye,eAAgB,GAGtB/hB,EAAOyC,MAAMoe,SAAU,SAAUvd,KAAMb,GAAO,OAGzC,IAGRzC,EAAOyC,MAAM6K,IAAKhK,KAAM,yBAA0B,SAAUwE,GAC3D,GAAIzE,GAAOyE,EAAEtB,MAERuU,GAAWhX,KAAMV,EAAK2G,YAAehK,EAAO0V,MAAOrS,EAAM,mBAC7DrD,EAAOyC,MAAM6K,IAAKjK,EAAM,iBAAkB,SAAUZ,IAC9Ca,KAAKc,YAAe3B,EAAMse,aAAgBte,EAAM+a,WACpDxd,EAAOyC,MAAMoe,SAAU,SAAUvd,KAAKc,WAAY3B,GAAO,KAG3DzC,EAAO0V,MAAOrS,EAAM,iBAAiB,MATvCrD,IAcDmc,OAAQ,SAAU1Z,GACjB,GAAIY,GAAOZ,EAAM+D,MAGjB,OAAKlD,QAASD,GAAQZ,EAAMse,aAAete,EAAM+a,WAA4B,UAAdna,EAAKV,MAAkC,aAAdU,EAAKV,KACrFF,EAAMqZ,UAAUN,QAAQnW,MAAO/B,KAAMgC,WAD7C,GAKD2X,SAAU,WAGT,MAFAjd,GAAOyC,MAAMiG,OAAQpF,KAAM,aAEnByX,EAAWhX,KAAMT,KAAK0G,aAM3BhK,EAAO6P,QAAQmS,gBACpBhiB,EAAOgF,MAAOwb,MAAO,UAAWE,KAAM,YAAc,SAAUa,EAAMrD,GAGnE,GAAI+D,GAAW,EACdzG,EAAU,SAAU/Y,GACnBzC,EAAOyC,MAAMoe,SAAU3C,EAAKzb,EAAM+D,OAAQxG,EAAOyC,MAAMyb,IAAKzb,IAAS,GAGvEzC,GAAOyC,MAAMmZ,QAASsC,IACrBrB,MAAO,WACc,IAAfoF,KACJpiB,EAAS6C,iBAAkB6e,EAAM/F,GAAS,IAG5CyB,SAAU,WACW,MAAbgF,GACNpiB,EAASkD,oBAAqBwe,EAAM/F,GAAS,OAOlDxb,EAAOsB,GAAG2E,QAETic,GAAI,SAAU3G,EAAOna,EAAUgH,EAAM9G,EAAiByX,GACrD,GAAIpW,GAAMwf,CAGV,IAAsB,gBAAV5G,GAAqB,CAEP,gBAAbna,KAEXgH,EAAOA,GAAQhH,EACfA,EAAW3B,EAEZ,KAAMkD,IAAQ4Y,GACbjY,KAAK4e,GAAIvf,EAAMvB,EAAUgH,EAAMmT,EAAO5Y,GAAQoW,EAE/C,OAAOzV,MAmBR,GAhBa,MAAR8E,GAAsB,MAAN9G,GAEpBA,EAAKF,EACLgH,EAAOhH,EAAW3B,GACD,MAAN6B,IACc,gBAAbF,IAEXE,EAAK8G,EACLA,EAAO3I,IAGP6B,EAAK8G,EACLA,EAAOhH,EACPA,EAAW3B,IAGR6B,KAAO,EACXA,EAAK+Z,OACC,KAAM/Z,EACZ,MAAOgC,KAaR,OAVa,KAARyV,IACJoJ,EAAS7gB,EACTA,EAAK,SAAUmB,GAGd,MADAzC,KAASqH,IAAK5E,GACP0f,EAAO9c,MAAO/B,KAAMgC,YAG5BhE,EAAG2J,KAAOkX,EAAOlX,OAAUkX,EAAOlX,KAAOjL,EAAOiL,SAE1C3H,KAAK0B,KAAM,WACjBhF,EAAOyC,MAAM6K,IAAKhK,KAAMiY,EAAOja,EAAI8G,EAAMhH,MAG3C2X,IAAK,SAAUwC,EAAOna,EAAUgH,EAAM9G,GACrC,MAAOgC,MAAK4e,GAAI3G,EAAOna,EAAUgH,EAAM9G,EAAI,IAE5C+F,IAAK,SAAUkU,EAAOna,EAAUE,GAC/B,GAAIwa,GAAWnZ,CACf,IAAK4Y,GAASA,EAAMwC,gBAAkBxC,EAAMO,UAQ3C,MANAA,GAAYP,EAAMO,UAClB9b,EAAQub,EAAM8C,gBAAiBhX,IAC9ByU,EAAUY,UAAYZ,EAAUG,SAAW,IAAMH,EAAUY,UAAYZ,EAAUG,SACjFH,EAAU1a,SACV0a,EAAUN,SAEJlY,IAER,IAAsB,gBAAViY,GAAqB,CAEhC,IAAM5Y,IAAQ4Y,GACbjY,KAAK+D,IAAK1E,EAAMvB,EAAUma,EAAO5Y,GAElC,OAAOW,MAUR,OARKlC,KAAa,GAA6B,kBAAbA,MAEjCE,EAAKF,EACLA,EAAW3B,GAEP6B,KAAO,IACXA,EAAK+Z,IAEC/X,KAAK0B,KAAK,WAChBhF,EAAOyC,MAAMiG,OAAQpF,KAAMiY,EAAOja,EAAIF,MAIxCghB,KAAM,SAAU7G,EAAOnT,EAAM9G,GAC5B,MAAOgC,MAAK4e,GAAI3G,EAAO,KAAMnT,EAAM9G,IAEpC+gB,OAAQ,SAAU9G,EAAOja,GACxB,MAAOgC,MAAK+D,IAAKkU,EAAO,KAAMja,IAG/BghB,SAAU,SAAUlhB,EAAUma,EAAOnT,EAAM9G,GAC1C,MAAOgC,MAAK4e,GAAI3G,EAAOna,EAAUgH,EAAM9G,IAExCihB,WAAY,SAAUnhB,EAAUma,EAAOja,GAEtC,MAA4B,KAArBgE,UAAU9B,OAAeF,KAAK+D,IAAKjG,EAAU,MAASkC,KAAK+D,IAAKkU,EAAOna,GAAY,KAAME,IAGjG8F,QAAS,SAAUzE,EAAMyF,GACxB,MAAO9E,MAAK0B,KAAK,WAChBhF,EAAOyC,MAAM2E,QAASzE,EAAMyF,EAAM9E,SAGpCkf,eAAgB,SAAU7f,EAAMyF,GAC/B,GAAI/E,GAAOC,KAAK,EAChB,OAAKD,GACGrD,EAAOyC,MAAM2E,QAASzE,EAAMyF,EAAM/E,GAAM,GADhD,KAWF,SAAW7D,EAAQC,GAEnB,GAAIiG,GACH+c,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EAGAC,EACAnjB,EACAojB,EACAC,EACAC,EACAC,EACAxE,EACA6C,EACA4B,EAGAnQ,EAAU,UAAY,GAAKzH,MAC3B6X,EAAe9jB,EAAOK,SACtBgQ,KACA0T,EAAU,EACVne,EAAO,EACPoe,EAAaC,KACbC,EAAaD,KACbE,EAAgBF,KAGhBG,QAAsBnkB,GACtBokB,EAAe,GAAK,GAGpBxZ,KACA0K,EAAM1K,EAAI0K,IACVtU,EAAO4J,EAAI5J,KACXE,EAAQ0J,EAAI1J,MAEZE,EAAUwJ,EAAIxJ,SAAW,SAAUwC,GAClC,GAAIqC,GAAI,EACPC,EAAMrC,KAAKE,MACZ,MAAYmC,EAAJD,EAASA,IAChB,GAAKpC,KAAKoC,KAAOrC,EAChB,MAAOqC,EAGT,OAAO,IAORoe,EAAa,sBAEbC,EAAoB,mCAKpBC,EAAaD,EAAkBhb,QAAS,IAAK,MAG7Ckb,EAAY,eACZhR,EAAa,MAAQ6Q,EAAa,KAAOC,EAAoB,IAAMD,EAClE,OAASG,EAAYH,EAAa,wCAA0CE,EAAa,QAAUF,EAAa,OAQjHI,EAAU,KAAOH,EAAoB,mEAAqE9Q,EAAWlK,QAAS,EAAG,GAAM,eAGvIpH,EAAYqb,OAAQ,IAAM8G,EAAa,8BAAgCA,EAAa,KAAM,KAE1FK,EAAanH,OAAQ,IAAM8G,EAAa,KAAOA,EAAa,KAC5DM,EAAmBpH,OAAQ,IAAM8G,EAAa,4BAA8BA,EAAa,KACzFO,EAAcrH,OAAQkH,GACtBI,EAAkBtH,OAAQ,IAAMgH,EAAa,KAE7CO,GACCC,GAAUxH,OAAQ,MAAQ+G,EAAoB,KAC9CU,MAAazH,OAAQ,QAAU+G,EAAoB,KACnDW,KAAY1H,OAAQ,mBAAqB+G,EAAoB,cAC7DY,IAAW3H,OAAQ,KAAO+G,EAAkBhb,QAAS,IAAK,MAAS,KACnE6b,KAAY5H,OAAQ,IAAM/J,GAC1B4R,OAAc7H,OAAQ,IAAMkH,GAC5BY,MAAa9H,OAAQ,yDAA2D8G,EAC/E,+BAAiCA,EAAa,cAAgBA,EAC9D,aAAeA,EAAa,SAAU,KAGvCtH,aAAoBQ,OAAQ,IAAM8G,EAAa,mDAC9CA,EAAa,mBAAqBA,EAAa,mBAAoB,MAGrEiB,EAAW,sBAEXC,EAAU,2BAGVpjB,EAAa,mCAEbqjB,EAAU,sCACVC,EAAU,SAEVC,EAAU,QACVC,EAAmB,gDAGnBC,GAAY,wCACZC,GAAY,SAAUjZ,EAAGkZ,GACxB,GAAIC,GAAO,KAAOD,EAAU,KAE5B,OAAOC,KAASA,EACfD,EAEO,EAAPC,EACC3d,OAAO4d,aAAcD,EAAO,OAE5B3d,OAAO4d,aAA2B,MAAbD,GAAQ,GAA4B,MAAR,KAAPA,GAI9C,KACC7kB,EAAM8D,KAAM6e,EAAa7Z,gBAAgBd,WAAY,GAAI,GAAG9E,SAC3D,MAAQiE,IACTnH,EAAQ,SAAU+E,GACjB,GAAIrC,GACHiH,IACD,OAASjH,EAAOC,KAAKoC,KACpB4E,EAAQ7J,KAAM4C,EAEf,OAAOiH,IAQT,QAASob,IAAUpkB,GAClB,MAAO0jB,GAAQjhB,KAAMzC,EAAK,IAS3B,QAASmiB,MACR,GAAI3O,GACH6Q,IAED,OAAQ7Q,GAAQ,SAAU/M,EAAKmC,GAM9B,MAJKyb,GAAKllB,KAAMsH,GAAO,KAAQ2a,EAAKkD,mBAE5B9Q,GAAO6Q,EAAKxY,SAEZ2H,EAAO/M,GAAQmC,GAQzB,QAAS2b,IAAcvkB,GAEtB,MADAA,GAAI4R,IAAY,EACT5R,EAOR,QAASwkB,IAAQxkB,GAChB,GAAI+O,GAAMxQ,EAAS2I,cAAc,MAEjC,KACC,MAAOlH,GAAI+O,GACV,MAAOvI,GACR,OAAO,EACN,QAEDuI,EAAM,MAIR,QAAS0V,IAAQ3kB,EAAUC,EAASiJ,EAAS0b,GAC5C,GAAI5iB,GAAOC,EAAM4iB,EAAGpiB,EAEnB6B,EAAGwgB,EAAQC,EAAKC,EAAKC,EAAYC,CASlC,KAPOjlB,EAAUA,EAAQyC,eAAiBzC,EAAUiiB,KAAmBzjB,GACtEmjB,EAAa3hB,GAGdA,EAAUA,GAAWxB,EACrByK,EAAUA,OAEJlJ,GAAgC,gBAAbA,GACxB,MAAOkJ,EAGR,IAAuC,KAAjCzG,EAAWxC,EAAQwC,WAAgC,IAAbA,EAC3C,QAGD,KAAMqf,IAAkB8C,EAAO,CAG9B,GAAM5iB,EAAQxB,EAAW6B,KAAMrC,GAE9B,GAAM6kB,EAAI7iB,EAAM,IACf,GAAkB,IAAbS,EAAiB,CAIrB,GAHAR,EAAOhC,EAAQ8C,eAAgB8hB,IAG1B5iB,IAAQA,EAAKe,WAQjB,MAAOkG,EALP,IAAKjH,EAAKgB,KAAO4hB,EAEhB,MADA3b,GAAQ7J,KAAM4C,GACPiH,MAOT,IAAKjJ,EAAQyC,gBAAkBT,EAAOhC,EAAQyC,cAAcK,eAAgB8hB,KAC3ExE,EAAUpgB,EAASgC,IAAUA,EAAKgB,KAAO4hB,EAEzC,MADA3b,GAAQ7J,KAAM4C,GACPiH,MAKH,CAAA,GAAKlH,EAAM,GAEjB,MADA3C,GAAK4E,MAAOiF,EAAS3J,EAAM8D,KAAKpD,EAAQqI,qBAAsBtI,GAAY,IACnEkJ,CAGD,KAAM2b,EAAI7iB,EAAM,KAAOyM,EAAQ0W,gBAAkBllB,EAAQmlB,uBAE/D,MADA/lB,GAAK4E,MAAOiF,EAAS3J,EAAM8D,KAAKpD,EAAQmlB,uBAAwBP,GAAK,IAC9D3b,EAKT,GAAKuF,EAAQ4W,MAAQtD,EAAUpf,KAAK3C,GAAY,CAU/C,GATA+kB,GAAM,EACNC,EAAMlT,EACNmT,EAAahlB,EACbilB,EAA2B,IAAbziB,GAAkBzC,EAMd,IAAbyC,GAAqD,WAAnCxC,EAAQ2I,SAASC,cAA6B,CACpEic,EAASQ,GAAUtlB,IAEb+kB,EAAM9kB,EAAQ4P,aAAa,OAChCmV,EAAMD,EAAIpd,QAASoc,EAAS,QAE5B9jB,EAAQiP,aAAc,KAAM8V,GAE7BA,EAAM,QAAUA,EAAM,MAEtB1gB,EAAIwgB,EAAO1iB,MACX,OAAQkC,IACPwgB,EAAOxgB,GAAK0gB,EAAMO,GAAYT,EAAOxgB,GAEtC2gB,GAAatB,EAAShhB,KAAM3C,IAAcC,EAAQ+C,YAAc/C,EAChEilB,EAAcJ,EAAOvJ,KAAK,KAG3B,GAAK2J,EACJ,IAIC,MAHA7lB,GAAK4E,MAAOiF,EAAS3J,EAAM8D,KAAM4hB,EAAWO,iBAC3CN,GACE,IACIhc,EACN,MAAMuc,IACN,QACKV,GACL9kB,EAAQiY,gBAAgB,QAQ7B,MAAOtJ,IAAQ5O,EAAS2H,QAASpH,EAAO,MAAQN,EAASiJ,EAAS0b,GAOnEpD,EAAQmD,GAAOnD,MAAQ,SAAUvf,GAGhC,GAAIoG,GAAkBpG,IAASA,EAAKS,eAAiBT,GAAMoG,eAC3D,OAAOA,GAA+C,SAA7BA,EAAgBO,UAAsB,GAQhEgZ,EAAc+C,GAAO/C,YAAc,SAAU8D,GAC5C,GAAInH,GAAMmH,EAAOA,EAAKhjB,eAAiBgjB,EAAOxD,CAG9C,OAAK3D,KAAQ9f,GAA6B,IAAjB8f,EAAI9b,UAAmB8b,EAAIlW,iBAKpD5J,EAAW8f,EACXsD,EAAUtD,EAAIlW,gBAGdyZ,EAAgBN,EAAOjD,GAGvB9P,EAAQkX,kBAAoBjB,GAAO,SAAUzV,GAE5C,MADAA,GAAIG,YAAamP,EAAIqH,cAAc,MAC3B3W,EAAI3G,qBAAqB,KAAKlG,SAIvCqM,EAAQoD,WAAa6S,GAAO,SAAUzV,GACrCA,EAAIE,UAAY,mBAChB,IAAI5N,SAAc0N,GAAIuC,UAAU3B,aAAa,WAE7C,OAAgB,YAATtO,GAA+B,WAATA,IAI9BkN,EAAQ0W,eAAiBT,GAAO,SAAUzV,GAGzC,MADAA,GAAIE,UAAY,yDACVF,EAAImW,wBAA2BnW,EAAImW,uBAAuB,KAAKhjB,QAKrE6M,EAAIuC,UAAUhC,UAAY,IACwB,IAA3CP,EAAImW,uBAAuB,KAAKhjB,SAL/B,IAUTqM,EAAQ+E,UAAYkR,GAAO,SAAUzV,GAEpCA,EAAIhM,GAAK6O,EAAU,EACnB7C,EAAIE,UAAY,YAAc2C,EAAU,oBAAsBA,EAAU,WACxE+P,EAAQgE,aAAc5W,EAAK4S,EAAQnS,WAGnC,IAAIoW,GAAOvH,EAAIwH,mBAEdxH,EAAIwH,kBAAmBjU,GAAU1P,SAAW,EAE5Cmc,EAAIwH,kBAAmBjU,EAAU,GAAI1P,MAMtC,OALAqM,GAAQuX,cAAgBzH,EAAIxb,eAAgB+O,GAG5C+P,EAAQ7O,YAAa/D,GAEd6W,IAIRxE,EAAK2E,WAAavB,GAAO,SAAUzV,GAElC,MADAA,GAAIE,UAAY,mBACTF,EAAIS,kBAAqBT,GAAIS,WAAWG,eAAiB2S,GACvB,MAAxCvT,EAAIS,WAAWG,aAAa,cAI5BuJ,KAAQ,SAAUnX,GACjB,MAAOA,GAAK4N,aAAc,OAAQ,IAEnCtO,KAAQ,SAAUU,GACjB,MAAOA,GAAK4N,aAAa,UAKvBpB,EAAQuX,cACZ1E,EAAKhf,KAAS,GAAI,SAAUW,EAAIhD,GAC/B,SAAYA,GAAQ8C,iBAAmByf,IAAiBV,EAAgB,CACvE,GAAI+C,GAAI5kB,EAAQ8C,eAAgBE,EAGhC,OAAO4hB,IAAKA,EAAE7hB,YAAc6hB,QAG9BvD,EAAKrD,OAAW,GAAI,SAAUhb,GAC7B,GAAIijB,GAASjjB,EAAG0E,QAASsc,GAAWC,GACpC,OAAO,UAAUjiB,GAChB,MAAOA,GAAK4N,aAAa,QAAUqW,MAIrC5E,EAAKhf,KAAS,GAAI,SAAUW,EAAIhD,GAC/B,SAAYA,GAAQ8C,iBAAmByf,IAAiBV,EAAgB,CACvE,GAAI+C,GAAI5kB,EAAQ8C,eAAgBE,EAEhC,OAAO4hB,GACNA,EAAE5hB,KAAOA,SAAa4hB,GAAE3L,mBAAqBsJ,GAAgBqC,EAAE3L,iBAAiB,MAAMpQ,QAAU7F,GAC9F4hB,GACDxmB,OAIJijB,EAAKrD,OAAW,GAAK,SAAUhb,GAC9B,GAAIijB,GAASjjB,EAAG0E,QAASsc,GAAWC,GACpC,OAAO,UAAUjiB,GAChB,GAAIyjB,SAAczjB,GAAKiX,mBAAqBsJ,GAAgBvgB,EAAKiX,iBAAiB,KAClF,OAAOwM,IAAQA,EAAK5c,QAAUod,KAMjC5E,EAAKhf,KAAU,IAAImM,EAAQkX,kBAC1B,SAAUQ,EAAKlmB,GACd,aAAYA,GAAQqI,uBAAyBka,EACrCviB,EAAQqI,qBAAsB6d,GADtC,GAID,SAAUA,EAAKlmB,GACd,GAAIgC,GACH8F,KACAzD,EAAI,EACJ4E,EAAUjJ,EAAQqI,qBAAsB6d,EAGzC,IAAa,MAARA,EAAc,CAClB,MAASlkB,EAAOiH,EAAQ5E,KACA,IAAlBrC,EAAKQ,UACTsF,EAAI1I,KAAM4C,EAIZ,OAAO8F,GAER,MAAOmB,IAIToY,EAAKhf,KAAW,KAAImM,EAAQ+E,WAAa,SAAU2S,EAAKlmB,GACvD,aAAYA,GAAQ8lB,oBAAsBvD,EAClCviB,EAAQ8lB,kBAAmB9gB,MADnC,GAMDqc,EAAKhf,KAAY,MAAImM,EAAQ0W,gBAAkB,SAAU3V,EAAWvP,GACnE,aAAYA,GAAQmlB,yBAA2B5C,GAAiBV,EAAhE,EACQ7hB,EAAQmlB,uBAAwB5V,IAOzCwS,KAKAD,GAAc,WAERtT,EAAQ4W,IAAMf,GAAS/F,EAAIiH,qBAGhCd,GAAO,SAAUzV,GAMhBA,EAAIE,UAAY,iDAGVF,EAAIuW,iBAAiB,cAAcpjB,QACxC2f,EAAU1iB,KAAM,MAAQqjB,EAAa,gEAMhCzT,EAAIuW,iBAAiB,YAAYpjB,QACtC2f,EAAU1iB,KAAK,cAIjBqlB,GAAO,SAAUzV,GAIhBA,EAAIE,UAAY,8BACXF,EAAIuW,iBAAiB,WAAWpjB,QACpC2f,EAAU1iB,KAAM,SAAWqjB,EAAa,gBAKnCzT,EAAIuW,iBAAiB,YAAYpjB,QACtC2f,EAAU1iB,KAAM,WAAY,aAI7B4P,EAAIuW,iBAAiB,QACrBzD,EAAU1iB,KAAK,YAIXoP,EAAQ2X,gBAAkB9B,GAAW9G,EAAUqE,EAAQuE,iBAC5DvE,EAAQwE,oBACRxE,EAAQyE,uBACRzE,EAAQ0E,kBACR1E,EAAQ2E,qBAER9B,GAAO,SAAUzV,GAGhBR,EAAQgY,kBAAoBjJ,EAAQna,KAAM4L,EAAK,OAI/CuO,EAAQna,KAAM4L,EAAK,aACnB+S,EAAc3iB,KAAM,KAAMyjB,KAI5Bf,EAAgBnG,OAAQmG,EAAUxG,KAAK,MACvCyG,EAAoBpG,OAAQoG,EAAczG,KAAK,MAK/C8E,EAAWiE,GAASzC,EAAQxB,WAAawB,EAAQ6E,wBAChD,SAAUhY,EAAGiY,GACZ,GAAIC,GAAuB,IAAflY,EAAEjM,SAAiBiM,EAAErG,gBAAkBqG,EAClDmY,EAAMF,GAAKA,EAAE3jB,UACd,OAAO0L,KAAMmY,MAAWA,GAAwB,IAAjBA,EAAIpkB,YAClCmkB,EAAMvG,SACLuG,EAAMvG,SAAUwG,GAChBnY,EAAEgY,yBAA8D,GAAnChY,EAAEgY,wBAAyBG,MAG3D,SAAUnY,EAAGiY,GACZ,GAAKA,EACJ,MAASA,EAAIA,EAAE3jB,WACd,GAAK2jB,IAAMjY,EACV,OAAO,CAIV,QAAO,GAITuT,EAAYJ,EAAQ6E,wBACpB,SAAUhY,EAAGiY,GACZ,GAAIG,EAEJ,OAAKpY,KAAMiY,GACVjF,GAAe,EACR,IAGFoF,EAAUH,EAAED,yBAA2BhY,EAAEgY,yBAA2BhY,EAAEgY,wBAAyBC,IACrF,EAAVG,GAAepY,EAAE1L,YAAwC,KAA1B0L,EAAE1L,WAAWP,SAC3CiM,IAAM6P,GAAO8B,EAAU6B,EAAcxT,GAClC,GAEHiY,IAAMpI,GAAO8B,EAAU6B,EAAcyE,GAClC,EAED,EAES,EAAVG,EAAc,GAAK,EAGpBpY,EAAEgY,wBAA0B,GAAK,GAEzC,SAAUhY,EAAGiY,GACZ,GAAI3R,GACH1Q,EAAI,EACJyiB,EAAMrY,EAAE1L,WACR6jB,EAAMF,EAAE3jB,WACRgkB,GAAOtY,GACPuY,GAAON,EAGR,IAAKjY,IAAMiY,EAEV,MADAjF,IAAe,EACR,CAGD,KAAMqF,IAAQF,EACpB,MAAOnY,KAAM6P,EAAM,GAClBoI,IAAMpI,EAAM,EACZwI,EAAM,GACNF,EAAM,EACN,CAGK,IAAKE,IAAQF,EACnB,MAAOK,IAAcxY,EAAGiY,EAIzB3R,GAAMtG,CACN,OAASsG,EAAMA,EAAIhS,WAClBgkB,EAAG/R,QAASD,EAEbA,GAAM2R,CACN,OAAS3R,EAAMA,EAAIhS,WAClBikB,EAAGhS,QAASD,EAIb,OAAQgS,EAAG1iB,KAAO2iB,EAAG3iB,GACpBA,GAGD,OAAOA,GAEN4iB,GAAcF,EAAG1iB,GAAI2iB,EAAG3iB,IAGxB0iB,EAAG1iB,KAAO4d,EAAe,GACzB+E,EAAG3iB,KAAO4d,EAAe,EACzB,GAKFR,GAAe,GACd,EAAG,GAAG/c,KAAMsd,GACbxT,EAAQ0Y,iBAAmBzF,EAEpBjjB,GA9UCA,GAiVTkmB,GAAOnH,QAAU,SAAUnC,EAAMxF,GAChC,MAAO8O,IAAQtJ,EAAM,KAAM,KAAMxF,IAGlC8O,GAAOyB,gBAAkB,SAAUnkB,EAAMoZ,GAUxC,IAROpZ,EAAKS,eAAiBT,KAAWxD,GACvCmjB,EAAa3f,GAIdoZ,EAAOA,EAAK1T,QAASqc,EAAkB,aAGlCvV,EAAQ2X,iBAAoBtE,GAAmBE,GAAkBA,EAAcrf,KAAK0Y,IAAW0G,EAAUpf,KAAK0Y,IAClH,IACC,GAAI3X,GAAM8Z,EAAQna,KAAMpB,EAAMoZ,EAG9B,IAAK3X,GAAO+K,EAAQgY,mBAGlBxkB,EAAKxD,UAAuC,KAA3BwD,EAAKxD,SAASgE,SAChC,MAAOiB,GAEP,MAAMgD,IAGT,MAAOie,IAAQtJ,EAAM5c,EAAU,MAAOwD,IAAQG,OAAS,GAGxDuiB,GAAOtE,SAAW,SAAUpgB,EAASgC,GAKpC,OAHOhC,EAAQyC,eAAiBzC,KAAcxB,GAC7CmjB,EAAa3hB,GAEPogB,EAAUpgB,EAASgC,IAG3B0iB,GAAO7hB,KAAO,SAAUb,EAAMgD,GAC7B,GAAIoS,EAUJ,QAPOpV,EAAKS,eAAiBT,KAAWxD,GACvCmjB,EAAa3f,GAGR6f,IACL7c,EAAOA,EAAK4D,gBAEPwO,EAAMiK,EAAK2E,WAAYhhB,IACrBoS,EAAKpV,GAER6f,GAAiBrT,EAAQoD,WACtB5P,EAAK4N,aAAc5K,KAEjBoS,EAAMpV,EAAKiX,iBAAkBjU,KAAWhD,EAAK4N,aAAc5K,KAAYhD,EAAMgD,MAAW,EACjGA,EACAoS,GAAOA,EAAII,UAAYJ,EAAIvO,MAAQ,MAGrC6b,GAAO9d,MAAQ,SAAUC,GACxB,KAAUC,OAAO,0CAA4CD,IAI9D6d,GAAOyC,WAAa,SAAUle,GAC7B,GAAIjH,GACHolB,KACA/iB,EAAI,EACJE,EAAI,CAML,IAHAkd,GAAgBjT,EAAQ0Y,iBACxBje,EAAQvE,KAAMsd,GAETP,EAAe,CACnB,KAASzf,EAAOiH,EAAQ5E,GAAKA,IACvBrC,IAASiH,EAAS5E,EAAI,KAC1BE,EAAI6iB,EAAWhoB,KAAMiF,GAGvB,OAAQE,IACP0E,EAAQtE,OAAQyiB,EAAY7iB,GAAK,GAInC,MAAO0E,GAGR,SAASge,IAAcxY,EAAGiY,GACzB,GAAI3R,GAAM2R,GAAKjY,EACd4Y,EAAOtS,KAAU2R,EAAEY,aAAe9E,KAAoB/T,EAAE6Y,aAAe9E,EAGxE,IAAK6E,EACJ,MAAOA,EAIR,IAAKtS,EACJ,MAASA,EAAMA,EAAIwS,YAClB,GAAKxS,IAAQ2R,EACZ,MAAO,EAKV,OAAOjY,GAAI,EAAI,GAIhB,QAAS+Y,IAAmBlmB,GAC3B,MAAO,UAAUU,GAChB,GAAIgD,GAAOhD,EAAK2G,SAASC,aACzB,OAAgB,UAAT5D,GAAoBhD,EAAKV,OAASA,GAK3C,QAASmmB,IAAoBnmB,GAC5B,MAAO,UAAUU,GAChB,GAAIgD,GAAOhD,EAAK2G,SAASC,aACzB,QAAiB,UAAT5D,GAA6B,WAATA,IAAsBhD,EAAKV,OAASA,GAKlE,QAASomB,IAAwBznB,GAChC,MAAOukB,IAAa,SAAUmD,GAE7B,MADAA,IAAYA,EACLnD,GAAa,SAAUG,EAAMpH,GACnC,GAAIhZ,GACHqjB,EAAe3nB,KAAQ0kB,EAAKxiB,OAAQwlB,GACpCtjB,EAAIujB,EAAazlB,MAGlB,OAAQkC,IACFsgB,EAAOpgB,EAAIqjB,EAAavjB,MAC5BsgB,EAAKpgB,KAAOgZ,EAAQhZ,GAAKogB,EAAKpgB,SAWnC+c,EAAUoD,GAAOpD,QAAU,SAAUtf,GACpC,GAAIyjB,GACHhiB,EAAM,GACNY,EAAI,EACJ7B,EAAWR,EAAKQ,QAEjB,IAAMA,GAMC,GAAkB,IAAbA,GAA+B,IAAbA,GAA+B,KAAbA,EAAkB,CAGjE,GAAiC,gBAArBR,GAAK6lB,YAChB,MAAO7lB,GAAK6lB,WAGZ,KAAM7lB,EAAOA,EAAKyN,WAAYzN,EAAMA,EAAOA,EAAKulB,YAC/C9jB,GAAO6d,EAAStf,OAGZ,IAAkB,IAAbQ,GAA+B,IAAbA,EAC7B,MAAOR,GAAK8lB,cAhBZ,MAASrC,EAAOzjB,EAAKqC,GAAKA,IAEzBZ,GAAO6d,EAASmE,EAkBlB,OAAOhiB,IAGR4d,EAAOqD,GAAOqD,WAGbxD,YAAa,GAEbyD,aAAcxD,GAEdziB,MAAOmhB,EAEP7gB,QAEA4lB,UACCC,KAAOC,IAAK,aAAcjkB,OAAO,GACjCkkB,KAAOD,IAAK,cACZE,KAAOF,IAAK,kBAAmBjkB,OAAO,GACtCokB,KAAOH,IAAK,oBAGbI,WACChF,KAAQ,SAAUxhB,GAUjB,MATAA,GAAM,GAAKA,EAAM,GAAG2F,QAASsc,GAAWC,IAGxCliB,EAAM,IAAOA,EAAM,IAAMA,EAAM,IAAM,IAAK2F,QAASsc,GAAWC,IAE5C,OAAbliB,EAAM,KACVA,EAAM,GAAK,IAAMA,EAAM,GAAK,KAGtBA,EAAMzC,MAAO,EAAG,IAGxBmkB,MAAS,SAAU1hB,GA6BlB,MAlBAA,GAAM,GAAKA,EAAM,GAAG6G,cAEY,QAA3B7G,EAAM,GAAGzC,MAAO,EAAG,IAEjByC,EAAM,IACX2iB,GAAO9d,MAAO7E,EAAM,IAKrBA,EAAM,KAAQA,EAAM,GAAKA,EAAM,IAAMA,EAAM,IAAM,GAAK,GAAmB,SAAbA,EAAM,IAA8B,QAAbA,EAAM,KACzFA,EAAM,KAAUA,EAAM,GAAKA,EAAM,IAAqB,QAAbA,EAAM,KAGpCA,EAAM,IACjB2iB,GAAO9d,MAAO7E,EAAM,IAGdA,GAGRyhB,OAAU,SAAUzhB,GACnB,GAAIymB,GACHC,GAAY1mB,EAAM,IAAMA,EAAM,EAE/B,OAAKmhB,GAAiB,MAAExgB,KAAMX,EAAM,IAC5B,MAIHA,EAAM,GACVA,EAAM,GAAKA,EAAM,GAGN0mB,GAAYzF,EAAQtgB,KAAM+lB,KAEpCD,EAASnD,GAAUoD,GAAU,MAE7BD,EAASC,EAASjpB,QAAS,IAAKipB,EAAStmB,OAASqmB,GAAWC,EAAStmB,UAGvEJ,EAAM,GAAKA,EAAM,GAAGzC,MAAO,EAAGkpB,GAC9BzmB,EAAM,GAAK0mB,EAASnpB,MAAO,EAAGkpB,IAIxBzmB,EAAMzC,MAAO,EAAG,MAIzB0e,QAECsF,IAAO,SAAU3a,GAChB,MAAkB,MAAbA,EACG,WAAa,OAAO,IAG5BA,EAAWA,EAASjB,QAASsc,GAAWC,IAAYrb,cAC7C,SAAU5G,GAChB,MAAOA,GAAK2G,UAAY3G,EAAK2G,SAASC,gBAAkBD,KAI1Dya,MAAS,SAAU7T,GAClB,GAAImZ,GAAUvG,EAAY5S,EAAY,IAEtC,OAAOmZ,KACLA,EAAc/M,OAAQ,MAAQ8G,EAAa,IAAMlT,EAAY,IAAMkT,EAAa,SACjFN,EAAY5S,EAAW,SAAUvN,GAChC,MAAO0mB,GAAQhmB,KAAMV,EAAKuN,iBAAqBvN,GAAK4N,eAAiB2S,GAAgBvgB,EAAK4N,aAAa,UAAa,OAIvH2T,KAAQ,SAAUve,EAAM2jB,EAAUC,GACjC,MAAO,UAAU5mB,GAChB,GAAIqa,GAASqI,GAAO7hB,KAAMb,EAAMgD,EAEhC,OAAe,OAAVqX,EACgB,OAAbsM,EAEFA,GAINtM,GAAU,GAEU,MAAbsM,EAAmBtM,IAAWuM,EACvB,OAAbD,EAAoBtM,IAAWuM,EAClB,OAAbD,EAAoBC,GAAqC,IAA5BvM,EAAO7c,QAASopB,GAChC,OAAbD,EAAoBC,GAASvM,EAAO7c,QAASopB,GAAU,GAC1C,OAAbD,EAAoBC,GAASvM,EAAO/c,OAAQspB,EAAMzmB,UAAaymB,EAClD,OAAbD,GAAsB,IAAMtM,EAAS,KAAM7c,QAASopB,GAAU,GACjD,OAAbD,EAAoBtM,IAAWuM,GAASvM,EAAO/c,MAAO,EAAGspB,EAAMzmB,OAAS,KAAQymB,EAAQ,KACxF,IAZO,IAgBVnF,MAAS,SAAUniB,EAAMunB,EAAMlB,EAAUzjB,EAAOE,GAC/C,GAAI0kB,GAAgC,QAAvBxnB,EAAKhC,MAAO,EAAG,GAC3BypB,EAA+B,SAArBznB,EAAKhC,MAAO,IACtB0pB,EAAkB,YAATH,CAEV,OAAiB,KAAV3kB,GAAwB,IAATE,EAGrB,SAAUpC,GACT,QAASA,EAAKe,YAGf,SAAUf,EAAMhC,EAAS6H,GACxB,GAAI4L,GAAOwV,EAAYxD,EAAM4B,EAAM6B,EAAWhd,EAC7Cic,EAAMW,IAAWC,EAAU,cAAgB,kBAC3CtP,EAASzX,EAAKe,WACdiC,EAAOgkB,GAAUhnB,EAAK2G,SAASC,cAC/BugB,GAAYthB,IAAQmhB,CAErB,IAAKvP,EAAS,CAGb,GAAKqP,EAAS,CACb,MAAQX,EAAM,CACb1C,EAAOzjB,CACP,OAASyjB,EAAOA,EAAM0C,GACrB,GAAKa,EAASvD,EAAK9c,SAASC,gBAAkB5D,EAAyB,IAAlBygB,EAAKjjB,SACzD,OAAO,CAIT0J,GAAQic,EAAe,SAAT7mB,IAAoB4K,GAAS,cAE5C,OAAO,EAMR,GAHAA,GAAU6c,EAAUtP,EAAOhK,WAAagK,EAAOlI,WAG1CwX,GAAWI,EAAW,CAE1BF,EAAaxP,EAAQ5H,KAAc4H,EAAQ5H,OAC3C4B,EAAQwV,EAAY3nB,OACpB4nB,EAAYzV,EAAM,KAAOyO,GAAWzO,EAAM,GAC1C4T,EAAO5T,EAAM,KAAOyO,GAAWzO,EAAM,GACrCgS,EAAOyD,GAAazP,EAAOnS,WAAY4hB,EAEvC,OAASzD,IAASyD,GAAazD,GAAQA,EAAM0C,KAG3Cd,EAAO6B,EAAY,IAAMhd,EAAMwH,MAGhC,GAAuB,IAAlB+R,EAAKjjB,YAAoB6kB,GAAQ5B,IAASzjB,EAAO,CACrDinB,EAAY3nB,IAAW4gB,EAASgH,EAAW7B,EAC3C,YAKI,IAAK8B,IAAa1V,GAASzR,EAAM6P,KAAc7P,EAAM6P,QAAkBvQ,KAAWmS,EAAM,KAAOyO,EACrGmF,EAAO5T,EAAM,OAKb,OAASgS,IAASyD,GAAazD,GAAQA,EAAM0C,KAC3Cd,EAAO6B,EAAY,IAAMhd,EAAMwH,MAEhC,IAAOsV,EAASvD,EAAK9c,SAASC,gBAAkB5D,EAAyB,IAAlBygB,EAAKjjB,aAAsB6kB,IAE5E8B,KACH1D,EAAM5T,KAAc4T,EAAM5T,QAAkBvQ,IAAW4gB,EAASmF,IAG7D5B,IAASzjB,GACb,KAQJ,OADAqlB,IAAQjjB,EACDijB,IAASnjB,GAA4B,IAAjBmjB,EAAOnjB,GAAemjB,EAAOnjB,GAAS,KAKrEsf,OAAU,SAAU4F,EAAQzB,GAK3B,GAAI9jB,GACH5D,EAAKohB,EAAKwB,QAASuG,IAAY/H,EAAKgI,WAAYD,EAAOxgB,gBACtD8b,GAAO9d,MAAO,uBAAyBwiB,EAKzC,OAAKnpB,GAAI4R,GACD5R,EAAI0nB,GAIP1nB,EAAGkC,OAAS,GAChB0B,GAASulB,EAAQA,EAAQ,GAAIzB,GACtBtG,EAAKgI,WAAWzpB,eAAgBwpB,EAAOxgB,eAC7C4b,GAAa,SAAUG,EAAMpH,GAC5B,GAAI+L,GACHxM,EAAU7c,EAAI0kB,EAAMgD,GACpBtjB,EAAIyY,EAAQ3a,MACb,OAAQkC,IACPilB,EAAM9pB,EAAQ4D,KAAMuhB,EAAM7H,EAAQzY,IAClCsgB,EAAM2E,KAAW/L,EAAS+L,GAAQxM,EAAQzY,MAG5C,SAAUrC,GACT,MAAO/B,GAAI+B,EAAM,EAAG6B,KAIhB5D,IAIT4iB,SAEC0G,IAAO/E,GAAa,SAAUzkB,GAI7B,GAAI2O,MACHzF,KACAugB,EAAUhI,EAASzhB,EAAS2H,QAASpH,EAAO,MAE7C,OAAOkpB,GAAS3X,GACf2S,GAAa,SAAUG,EAAMpH,EAASvd,EAAS6H,GAC9C,GAAI7F,GACHynB,EAAYD,EAAS7E,EAAM,KAAM9c,MACjCxD,EAAIsgB,EAAKxiB,MAGV,OAAQkC,KACDrC,EAAOynB,EAAUplB,MACtBsgB,EAAKtgB,KAAOkZ,EAAQlZ,GAAKrC,MAI5B,SAAUA,EAAMhC,EAAS6H,GAGxB,MAFA6G,GAAM,GAAK1M,EACXwnB,EAAS9a,EAAO,KAAM7G,EAAKoB,IACnBA,EAAQyK,SAInBtH,IAAOoY,GAAa,SAAUzkB,GAC7B,MAAO,UAAUiC,GAChB,MAAO0iB,IAAQ3kB,EAAUiC,GAAOG,OAAS,KAI3Cie,SAAYoE,GAAa,SAAUzb,GAClC,MAAO,UAAU/G,GAChB,OAASA,EAAK6lB,aAAe7lB,EAAK0nB,WAAapI,EAAStf,IAASxC,QAASuJ,GAAS,MAWrF4gB,KAAQnF,GAAc,SAAUmF,GAM/B,MAJM1G,GAAYvgB,KAAKinB,GAAQ,KAC9BjF,GAAO9d,MAAO,qBAAuB+iB,GAEtCA,EAAOA,EAAKjiB,QAASsc,GAAWC,IAAYrb,cACrC,SAAU5G,GAChB,GAAI4nB,EACJ,GACC,IAAMA,EAAW/H,EAChB7f,EAAK4N,aAAa,aAAe5N,EAAK4N,aAAa,QACnD5N,EAAK2nB,KAGL,MADAC,GAAWA,EAAShhB,cACbghB,IAAaD,GAA2C,IAAnCC,EAASpqB,QAASmqB,EAAO,YAE5C3nB,EAAOA,EAAKe,aAAiC,IAAlBf,EAAKQ,SAC3C,QAAO,KAKT2C,OAAU,SAAUnD,GACnB,GAAI6nB,GAAO1rB,EAAOM,UAAYN,EAAOM,SAASorB,IAC9C,OAAOA,IAAQA,EAAKvqB,MAAO,KAAQ0C,EAAKgB,IAGzC8mB,KAAQ,SAAU9nB,GACjB,MAAOA,KAAS4f,GAGjBzC,MAAS,SAAUnd,GAClB,MAAOA,KAASxD,EAAS4gB,iBAAmB5gB,EAASurB,UAAYvrB,EAASurB,gBAAkB/nB,EAAKV,MAAQU,EAAKmX,OAASnX,EAAK+W,WAI7HiR,QAAW,SAAUhoB,GACpB,MAAOA,GAAKuK,YAAa,GAG1BA,SAAY,SAAUvK,GACrB,MAAOA,GAAKuK,YAAa,GAG1ByE,QAAW,SAAUhP,GAGpB,GAAI2G,GAAW3G,EAAK2G,SAASC,aAC7B,OAAqB,UAAbD,KAA0B3G,EAAKgP,SAA0B,WAAbrI,KAA2B3G,EAAKkO,UAGrFA,SAAY,SAAUlO,GAOrB,MAJKA,GAAKe,YACTf,EAAKe,WAAW0U,cAGVzV,EAAKkO,YAAa,GAI1B5D,MAAS,SAAUtK,GAMlB,IAAMA,EAAOA,EAAKyN,WAAYzN,EAAMA,EAAOA,EAAKulB,YAC/C,GAAKvlB,EAAK2G,SAAW,KAAyB,IAAlB3G,EAAKQ,UAAoC,IAAlBR,EAAKQ,SACvD,OAAO,CAGT,QAAO,GAGRiX,OAAU,SAAUzX,GACnB,OAAQqf,EAAKwB,QAAe,MAAG7gB,IAIhCioB,OAAU,SAAUjoB,GACnB,MAAO6hB,GAAQnhB,KAAMV,EAAK2G,WAG3B+F,MAAS,SAAU1M,GAClB,MAAO4hB,GAAQlhB,KAAMV,EAAK2G,WAG3B2Q,OAAU,SAAUtX,GACnB,GAAIgD,GAAOhD,EAAK2G,SAASC,aACzB,OAAgB,UAAT5D,GAAkC,WAAdhD,EAAKV,MAA8B,WAAT0D,GAGtD+D,KAAQ,SAAU/G,GACjB,GAAIa,EAGJ,OAAuC,UAAhCb,EAAK2G,SAASC,eACN,SAAd5G,EAAKV,OACmC,OAArCuB,EAAOb,EAAK4N,aAAa,UAAoB/M,EAAK+F,gBAAkB5G,EAAKV,OAI9E4C,MAASwjB,GAAuB,WAC/B,OAAS,KAGVtjB,KAAQsjB,GAAuB,SAAUE,EAAczlB,GACtD,OAASA,EAAS,KAGnBgC,GAAMujB,GAAuB,SAAUE,EAAczlB,EAAQwlB,GAC5D,OAAoB,EAAXA,EAAeA,EAAWxlB,EAASwlB,KAG7CuC,KAAQxC,GAAuB,SAAUE,EAAczlB,GACtD,GAAIkC,GAAI,CACR,MAAYlC,EAAJkC,EAAYA,GAAK,EACxBujB,EAAaxoB,KAAMiF,EAEpB,OAAOujB,KAGRuC,IAAOzC,GAAuB,SAAUE,EAAczlB,GACrD,GAAIkC,GAAI,CACR,MAAYlC,EAAJkC,EAAYA,GAAK,EACxBujB,EAAaxoB,KAAMiF,EAEpB,OAAOujB,KAGRwC,GAAM1C,GAAuB,SAAUE,EAAczlB,EAAQwlB,GAC5D,GAAItjB,GAAe,EAAXsjB,EAAeA,EAAWxlB,EAASwlB,CAC3C,QAAUtjB,GAAK,GACdujB,EAAaxoB,KAAMiF,EAEpB,OAAOujB,KAGRyC,GAAM3C,GAAuB,SAAUE,EAAczlB,EAAQwlB,GAC5D,GAAItjB,GAAe,EAAXsjB,EAAeA,EAAWxlB,EAASwlB,CAC3C,MAAcxlB,IAAJkC,GACTujB,EAAaxoB,KAAMiF,EAEpB,OAAOujB,MAMV,KAAMvjB,KAAOimB,OAAO,EAAMC,UAAU,EAAMC,MAAM,EAAMC,UAAU,EAAMC,OAAO,GAC5ErJ,EAAKwB,QAASxe,GAAMmjB,GAAmBnjB,EAExC,KAAMA,KAAOoN,QAAQ,EAAMkZ,OAAO,GACjCtJ,EAAKwB,QAASxe,GAAMojB,GAAoBpjB,EAGzC,SAASghB,IAAUtlB,EAAU6qB,GAC5B,GAAI9N,GAAS/a,EAAO8oB,EAAQvpB,EAC3BwpB,EAAOjG,EAAQkG,EACfC,EAAS3I,EAAYtiB,EAAW,IAEjC,IAAKirB,EACJ,MAAOJ,GAAY,EAAII,EAAO1rB,MAAO,EAGtCwrB,GAAQ/qB,EACR8kB,KACAkG,EAAa1J,EAAKkH,SAElB,OAAQuC,EAAQ,GAGThO,IAAY/a,EAAQ+gB,EAAO1gB,KAAM0oB,OACjC/oB,IAEJ+oB,EAAQA,EAAMxrB,MAAOyC,EAAM,GAAGI,SAAY2oB,GAE3CjG,EAAOzlB,KAAMyrB,OAGd/N,GAAU,GAGJ/a,EAAQghB,EAAa3gB,KAAM0oB,MAChChO,EAAU/a,EAAM+J,QAChB+e,EAAOzrB,MACNyJ,MAAOiU,EAEPxb,KAAMS,EAAM,GAAG2F,QAASpH,EAAO,OAEhCwqB,EAAQA,EAAMxrB,MAAOwd,EAAQ3a,QAI9B,KAAMb,IAAQ+f,GAAKrD,SACZjc,EAAQmhB,EAAW5hB,GAAOc,KAAM0oB,KAAcC,EAAYzpB,MAC9DS,EAAQgpB,EAAYzpB,GAAQS,MAC7B+a,EAAU/a,EAAM+J,QAChB+e,EAAOzrB,MACNyJ,MAAOiU,EACPxb,KAAMA,EACNic,QAASxb,IAEV+oB,EAAQA,EAAMxrB,MAAOwd,EAAQ3a,QAI/B,KAAM2a,EACL,MAOF,MAAO8N,GACNE,EAAM3oB,OACN2oB,EACCpG,GAAO9d,MAAO7G,GAEdsiB,EAAYtiB,EAAU8kB,GAASvlB,MAAO,GAGzC,QAASgmB,IAAYuF,GACpB,GAAIxmB,GAAI,EACPC,EAAMumB,EAAO1oB,OACbpC,EAAW,EACZ,MAAYuE,EAAJD,EAASA,IAChBtE,GAAY8qB,EAAOxmB,GAAGwE,KAEvB,OAAO9I,GAGR,QAASkrB,IAAezB,EAAS0B,EAAYC,GAC5C,GAAIhD,GAAM+C,EAAW/C,IACpBiD,EAAmBD,GAAgB,eAARhD,EAC3BkD,EAAWtnB,GAEZ,OAAOmnB,GAAWhnB,MAEjB,SAAUlC,EAAMhC,EAAS6H,GACxB,MAAS7F,EAAOA,EAAMmmB,GACrB,GAAuB,IAAlBnmB,EAAKQ,UAAkB4oB,EAC3B,MAAO5B,GAASxnB,EAAMhC,EAAS6H,IAMlC,SAAU7F,EAAMhC,EAAS6H,GACxB,GAAId,GAAM0M,EAAOwV,EAChBqC,EAASpJ,EAAU,IAAMmJ,CAG1B,IAAKxjB,GACJ,MAAS7F,EAAOA,EAAMmmB,GACrB,IAAuB,IAAlBnmB,EAAKQ,UAAkB4oB,IACtB5B,EAASxnB,EAAMhC,EAAS6H,GAC5B,OAAO,MAKV,OAAS7F,EAAOA,EAAMmmB,GACrB,GAAuB,IAAlBnmB,EAAKQ,UAAkB4oB,EAE3B,GADAnC,EAAajnB,EAAM6P,KAAc7P,EAAM6P,QACjC4B,EAAQwV,EAAYd,KAAU1U,EAAM,KAAO6X,GAChD,IAAMvkB,EAAO0M,EAAM,OAAQ,GAAQ1M,IAASqa,EAC3C,MAAOra,MAAS,MAKjB,IAFA0M,EAAQwV,EAAYd,IAAUmD,GAC9B7X,EAAM,GAAK+V,EAASxnB,EAAMhC,EAAS6H,IAASuZ,EACvC3N,EAAM,MAAO,EACjB,OAAO,GASf,QAAS8X,IAAgBC,GACxB,MAAOA,GAASrpB,OAAS,EACxB,SAAUH,EAAMhC,EAAS6H,GACxB,GAAIxD,GAAImnB,EAASrpB,MACjB,OAAQkC,IACP,IAAMmnB,EAASnnB,GAAIrC,EAAMhC,EAAS6H,GACjC,OAAO,CAGT,QAAO,GAER2jB,EAAS,GAGX,QAASC,IAAUhC,EAAWjlB,EAAKwZ,EAAQhe,EAAS6H,GACnD,GAAI7F,GACH0pB,KACArnB,EAAI,EACJC,EAAMmlB,EAAUtnB,OAChBwpB,EAAgB,MAAPnnB,CAEV,MAAYF,EAAJD,EAASA,KACVrC,EAAOynB,EAAUplB,OAChB2Z,GAAUA,EAAQhc,EAAMhC,EAAS6H,MACtC6jB,EAAatsB,KAAM4C,GACd2pB,GACJnnB,EAAIpF,KAAMiF,GAMd,OAAOqnB,GAGR,QAASE,IAAYrD,EAAWxoB,EAAUypB,EAASqC,EAAYC,EAAYC,GAO1E,MANKF,KAAeA,EAAYha,KAC/Bga,EAAaD,GAAYC,IAErBC,IAAeA,EAAYja,KAC/Bia,EAAaF,GAAYE,EAAYC,IAE/BvH,GAAa,SAAUG,EAAM1b,EAASjJ,EAAS6H,GACrD,GAAImkB,GAAM3nB,EAAGrC,EACZiqB,KACAC,KACAC,EAAcljB,EAAQ9G,OAGtBqB,EAAQmhB,GAAQyH,GAAkBrsB,GAAY,IAAKC,EAAQwC,UAAaxC,GAAYA,MAGpFqsB,GAAY9D,IAAe5D,GAAS5kB,EAEnCyD,EADAioB,GAAUjoB,EAAOyoB,EAAQ1D,EAAWvoB,EAAS6H,GAG9CykB,EAAa9C,EAEZsC,IAAgBnH,EAAO4D,EAAY4D,GAAeN,MAMjD5iB,EACDojB,CAQF,IALK7C,GACJA,EAAS6C,EAAWC,EAAYtsB,EAAS6H,GAIrCgkB,EAAa,CACjBG,EAAOP,GAAUa,EAAYJ,GAC7BL,EAAYG,KAAUhsB,EAAS6H,GAG/BxD,EAAI2nB,EAAK7pB,MACT,OAAQkC,KACDrC,EAAOgqB,EAAK3nB,MACjBioB,EAAYJ,EAAQ7nB,MAASgoB,EAAWH,EAAQ7nB,IAAOrC,IAK1D,GAAK2iB,GACJ,GAAKmH,GAAcvD,EAAY,CAC9B,GAAKuD,EAAa,CAEjBE,KACA3nB,EAAIioB,EAAWnqB,MACf,OAAQkC,KACDrC,EAAOsqB,EAAWjoB,KAEvB2nB,EAAK5sB,KAAOitB,EAAUhoB,GAAKrC,EAG7B8pB,GAAY,KAAOQ,KAAkBN,EAAMnkB,GAI5CxD,EAAIioB,EAAWnqB,MACf,OAAQkC,KACDrC,EAAOsqB,EAAWjoB,MACtB2nB,EAAOF,EAAatsB,EAAQ4D,KAAMuhB,EAAM3iB,GAASiqB,EAAO5nB,IAAM,KAE/DsgB,EAAKqH,KAAU/iB,EAAQ+iB,GAAQhqB,SAOlCsqB,GAAab,GACZa,IAAerjB,EACdqjB,EAAW3nB,OAAQwnB,EAAaG,EAAWnqB,QAC3CmqB,GAEGR,EACJA,EAAY,KAAM7iB,EAASqjB,EAAYzkB,GAEvCzI,EAAK4E,MAAOiF,EAASqjB,KAMzB,QAASC,IAAmB1B,GAC3B,GAAI2B,GAAchD,EAASjlB,EAC1BD,EAAMumB,EAAO1oB,OACbsqB,EAAkBpL,EAAK4G,SAAU4C,EAAO,GAAGvpB,MAC3CorB,EAAmBD,GAAmBpL,EAAK4G,SAAS,KACpD5jB,EAAIooB,EAAkB,EAAI,EAG1BE,EAAe1B,GAAe,SAAUjpB,GACvC,MAAOA,KAASwqB,GACdE,GAAkB,GACrBE,EAAkB3B,GAAe,SAAUjpB,GAC1C,MAAOxC,GAAQ4D,KAAMopB,EAAcxqB,GAAS,IAC1C0qB,GAAkB,GACrBlB,GAAa,SAAUxpB,EAAMhC,EAAS6H,GACrC,OAAU4kB,IAAqB5kB,GAAO7H,IAAY0hB,MAChD8K,EAAexsB,GAASwC,SACxBmqB,EAAc3qB,EAAMhC,EAAS6H,GAC7B+kB,EAAiB5qB,EAAMhC,EAAS6H,KAGpC,MAAYvD,EAAJD,EAASA,IAChB,GAAMmlB,EAAUnI,EAAK4G,SAAU4C,EAAOxmB,GAAG/C,MACxCkqB,GAAaP,GAAcM,GAAgBC,GAAYhC,QACjD,CAIN,GAHAA,EAAUnI,EAAKrD,OAAQ6M,EAAOxmB,GAAG/C,MAAO0C,MAAO,KAAM6mB,EAAOxmB,GAAGkZ,SAG1DiM,EAAS3X,GAAY,CAGzB,IADAtN,IAAMF,EACMC,EAAJC,EAASA,IAChB,GAAK8c,EAAK4G,SAAU4C,EAAOtmB,GAAGjD,MAC7B,KAGF,OAAOsqB,IACNvnB,EAAI,GAAKknB,GAAgBC,GACzBnnB,EAAI,GAAKihB,GAAYuF,EAAOvrB,MAAO,EAAG+E,EAAI,IAAMqD,QAASpH,EAAO,MAChEkpB,EACIjlB,EAAJF,GAASkoB,GAAmB1B,EAAOvrB,MAAO+E,EAAGE,IACzCD,EAAJC,GAAWgoB,GAAoB1B,EAASA,EAAOvrB,MAAOiF,IAClDD,EAAJC,GAAW+gB,GAAYuF,IAGzBW,EAASpsB,KAAMoqB,GAIjB,MAAO+B,IAAgBC,GAGxB,QAASqB,IAA0BC,EAAiBC,GAEnD,GAAIC,GAAoB,EACvBC,EAAQF,EAAY5qB,OAAS,EAC7B+qB,EAAYJ,EAAgB3qB,OAAS,EACrCgrB,EAAe,SAAUxI,EAAM3kB,EAAS6H,EAAKoB,EAASmkB,GACrD,GAAIprB,GAAMuC,EAAGilB,EACZ6D,KACAC,EAAe,EACfjpB,EAAI,IACJolB,EAAY9E,MACZ4I,EAA6B,MAAjBH,EACZI,EAAgB9L,EAEhBle,EAAQmhB,GAAQuI,GAAa7L,EAAKhf,KAAU,IAAG,IAAK+qB,GAAiBptB,EAAQ+C,YAAc/C,GAE3FytB,EAAiBvL,GAA4B,MAAjBsL,EAAwB,EAAIpkB,KAAK2K,UAAY,EAS1E,KAPKwZ,IACJ7L,EAAmB1hB,IAAYxB,GAAYwB,EAC3CohB,EAAa4L,GAKe,OAApBhrB,EAAOwB,EAAMa,IAAaA,IAAM,CACxC,GAAK6oB,GAAalrB,EAAO,CACxBuC,EAAI,CACJ,OAASilB,EAAUsD,EAAgBvoB,KAClC,GAAKilB,EAASxnB,EAAMhC,EAAS6H,GAAQ,CACpCoB,EAAQ7J,KAAM4C,EACd,OAGGurB,IACJrL,EAAUuL,EACVrM,IAAe4L,GAKZC,KAEEjrB,GAAQwnB,GAAWxnB,IACxBsrB,IAII3I,GACJ8E,EAAUrqB,KAAM4C,IAOnB,GADAsrB,GAAgBjpB,EACX4oB,GAAS5oB,IAAMipB,EAAe,CAClC/oB,EAAI,CACJ,OAASilB,EAAUuD,EAAYxoB,KAC9BilB,EAASC,EAAW4D,EAAYrtB,EAAS6H,EAG1C,IAAK8c,EAAO,CAEX,GAAK2I,EAAe,EACnB,MAAQjpB,IACAolB,EAAUplB,IAAMgpB,EAAWhpB,KACjCgpB,EAAWhpB,GAAKqP,EAAItQ,KAAM6F,GAM7BokB,GAAa5B,GAAU4B,GAIxBjuB,EAAK4E,MAAOiF,EAASokB,GAGhBE,IAAc5I,GAAQ0I,EAAWlrB,OAAS,GAC5CmrB,EAAeP,EAAY5qB,OAAW,GAExCuiB,GAAOyC,WAAYle,GAUrB,MALKskB,KACJrL,EAAUuL,EACV/L,EAAmB8L,GAGb/D,EAGT,OAAOwD,GACNzI,GAAc2I,GACdA,EAGF3L,EAAUkD,GAAOlD,QAAU,SAAUzhB,EAAU2tB,GAC9C,GAAIrpB,GACH0oB,KACAD,KACA9B,EAAS1I,EAAeviB,EAAW,IAEpC,KAAMirB,EAAS,CAER0C,IACLA,EAAQrI,GAAUtlB,IAEnBsE,EAAIqpB,EAAMvrB,MACV,OAAQkC,IACP2mB,EAASuB,GAAmBmB,EAAMrpB,IAC7B2mB,EAAQnZ,GACZkb,EAAY3tB,KAAM4rB,GAElB8B,EAAgB1tB,KAAM4rB,EAKxBA,GAAS1I,EAAeviB,EAAU8sB,GAA0BC,EAAiBC,IAE9E,MAAO/B,GAGR,SAASoB,IAAkBrsB,EAAUmO,EAAUjF,GAC9C,GAAI5E,GAAI,EACPC,EAAM4J,EAAS/L,MAChB,MAAYmC,EAAJD,EAASA,IAChBqgB,GAAQ3kB,EAAUmO,EAAS7J,GAAI4E,EAEhC,OAAOA,GAGR,QAAS0F,IAAQ5O,EAAUC,EAASiJ,EAAS0b,GAC5C,GAAItgB,GAAGwmB,EAAQ8C,EAAOrsB,EAAMe,EAC3BN,EAAQsjB,GAAUtlB,EAEnB,KAAM4kB,GAEiB,IAAjB5iB,EAAMI,OAAe,CAIzB,GADA0oB,EAAS9oB,EAAM,GAAKA,EAAM,GAAGzC,MAAO,GAC/BurB,EAAO1oB,OAAS,GAAkC,QAA5BwrB,EAAQ9C,EAAO,IAAIvpB,MACvB,IAArBtB,EAAQwC,WAAmBqf,GAC3BR,EAAK4G,SAAU4C,EAAO,GAAGvpB,MAAS,CAGnC,GADAtB,EAAUqhB,EAAKhf,KAAS,GAAGsrB,EAAMpQ,QAAQ,GAAG7V,QAASsc,GAAWC,IAAajkB,GAAU,IACjFA,EACL,MAAOiJ,EAGRlJ,GAAWA,EAAST,MAAOurB,EAAO/e,QAAQjD,MAAM1G,QAIjDkC,EAAI6e,EAAwB,aAAExgB,KAAM3C,GAAa,EAAI8qB,EAAO1oB,MAC5D,OAAQkC,IAAM,CAIb,GAHAspB,EAAQ9C,EAAOxmB,GAGVgd,EAAK4G,SAAW3mB,EAAOqsB,EAAMrsB,MACjC,KAED,KAAMe,EAAOgf,EAAKhf,KAAMf,MAEjBqjB,EAAOtiB,EACZsrB,EAAMpQ,QAAQ,GAAG7V,QAASsc,GAAWC,IACrCP,EAAShhB,KAAMmoB,EAAO,GAAGvpB,OAAUtB,EAAQ+C,YAAc/C,IACrD,CAKJ,GAFA6qB,EAAOlmB,OAAQN,EAAG,GAClBtE,EAAW4kB,EAAKxiB,QAAUmjB,GAAYuF,IAChC9qB,EAEL,MADAX,GAAK4E,MAAOiF,EAAS3J,EAAM8D,KAAMuhB,EAAM,IAChC1b,CAGR,SAgBL,MAPAuY,GAASzhB,EAAUgC,GAClB4iB,EACA3kB,EACA6hB,EACA5Y,EACAya,EAAShhB,KAAM3C,IAETkJ,EAIRoY,EAAKwB,QAAa,IAAIxB,EAAKwB,QAAY,EAGvC,SAASwG,OACThI,EAAKuM,QAAUvE,GAAWznB,UAAYyf,EAAKwB,QAC3CxB,EAAKgI,WAAa,GAAIA,IAGtB1H,IAGA+C,GAAO7hB,KAAOlE,EAAOkE,KACrBlE,EAAO0D,KAAOqiB,GACd/lB,EAAOyc,KAAOsJ,GAAOqD,UACrBppB,EAAOyc,KAAK,KAAOzc,EAAOyc,KAAKyH,QAC/BlkB,EAAOwN,OAASuY,GAAOyC,WACvBxoB,EAAOoK,KAAO2b,GAAOpD,QACrB3iB,EAAOkZ,SAAW6M,GAAOnD,MACzB5iB,EAAOyhB,SAAWsE,GAAOtE,UAGrBjiB,EACJ,IAAI0vB,IAAS,SACZC,GAAe,iCACfC,GAAW,iBACXC,GAAgBrvB,EAAOyc,KAAKrZ,MAAMoZ,aAElC8S,IACCC,UAAU,EACVC,UAAU,EACVrZ,MAAM,EACNsZ,MAAM,EAGRzvB,GAAOsB,GAAG2E,QACTvC,KAAM,SAAUtC,GACf,GAAIsE,GAAGZ,EAAKsI,EACXzH,EAAMrC,KAAKE,MAEZ,IAAyB,gBAAbpC,GAEX,MADAgM,GAAO9J,KACAA,KAAKsB,UAAW5E,EAAQoB,GAAWie,OAAO,WAChD,IAAM3Z,EAAI,EAAOC,EAAJD,EAASA,IACrB,GAAK1F,EAAOyhB,SAAUrU,EAAM1H,GAAKpC,MAChC,OAAO,IAOX,KADAwB,KACMY,EAAI,EAAOC,EAAJD,EAASA,IACrB1F,EAAO0D,KAAMtC,EAAUkC,KAAMoC,GAAKZ,EAMnC,OAFAA,GAAMxB,KAAKsB,UAAWe,EAAM,EAAI3F,EAAOwN,OAAQ1I,GAAQA,GACvDA,EAAI1D,UAAakC,KAAKlC,SAAWkC,KAAKlC,SAAW,IAAM,IAAOA,EACvD0D,GAGR2I,IAAK,SAAUjH,GACd,GAAId,GACHgqB,EAAU1vB,EAAQwG,EAAQlD,MAC1BqC,EAAM+pB,EAAQlsB,MAEf,OAAOF,MAAK+b,OAAO,WAClB,IAAM3Z,EAAI,EAAOC,EAAJD,EAASA,IACrB,GAAK1F,EAAOyhB,SAAUne,KAAMosB,EAAQhqB,IACnC,OAAO,KAMXklB,IAAK,SAAUxpB,GACd,MAAOkC,MAAKsB,UAAW+qB,GAAOrsB,KAAMlC,GAAU,KAG/Cie,OAAQ,SAAUje,GACjB,MAAOkC,MAAKsB,UAAW+qB,GAAOrsB,KAAMlC,GAAU,KAG/CwuB,GAAI,SAAUxuB,GACb,QAASA,IACY,gBAAbA,GAGNiuB,GAActrB,KAAM3C,GACnBpB,EAAQoB,EAAUkC,KAAKjC,SAAUqM,MAAOpK,KAAK,KAAQ,EACrDtD,EAAOqf,OAAQje,EAAUkC,MAAOE,OAAS,EAC1CF,KAAK+b,OAAQje,GAAWoC,OAAS,IAGpCqsB,QAAS,SAAUzG,EAAW/nB,GAC7B,GAAI+U,GACH1Q,EAAI,EACJkF,EAAItH,KAAKE,OACTsB,KACAgrB,EAAMT,GAActrB,KAAMqlB,IAAoC,gBAAdA,GAC/CppB,EAAQopB,EAAW/nB,GAAWiC,KAAKjC,SACnC,CAEF,MAAYuJ,EAAJlF,EAAOA,IAAM,CACpB0Q,EAAM9S,KAAKoC,EAEX,OAAQ0Q,GAAOA,EAAItS,eAAiBsS,IAAQ/U,GAA4B,KAAjB+U,EAAIvS,SAAkB,CAC5E,GAAKisB,EAAMA,EAAIpiB,MAAM0I,GAAO,GAAKpW,EAAO0D,KAAK8jB,gBAAgBpR,EAAKgT,GAAa,CAC9EtkB,EAAIrE,KAAM2V,EACV,OAEDA,EAAMA,EAAIhS,YAIZ,MAAOd,MAAKsB,UAAWE,EAAItB,OAAS,EAAIxD,EAAOwN,OAAQ1I,GAAQA,IAKhE4I,MAAO,SAAUrK,GAGhB,MAAMA,GAKe,gBAATA,GACJrD,EAAOwK,QAASlH,KAAK,GAAItD,EAAQqD,IAIlCrD,EAAOwK,QAEbnH,EAAKH,OAASG,EAAK,GAAKA,EAAMC,MAXrBA,KAAK,IAAMA,KAAK,GAAGc,WAAed,KAAKiC,QAAQwqB,UAAUvsB,OAAS,IAc7E8J,IAAK,SAAUlM,EAAUC,GACxB,GAAIsX,GAA0B,gBAAbvX,GACfpB,EAAQoB,EAAUC,GAClBrB,EAAOsE,UAAWlD,GAAYA,EAASyC,UAAazC,GAAaA,GAClEiB,EAAMrC,EAAO2D,MAAOL,KAAKoB,MAAOiU,EAEjC,OAAOrV,MAAKsB,UAAW5E,EAAOwN,OAAOnL,KAGtC2tB,QAAS,SAAU5uB,GAClB,MAAOkC,MAAKgK,IAAiB,MAAZlM,EAChBkC,KAAKyB,WAAazB,KAAKyB,WAAWsa,OAAOje,OAK5CpB,EAAOsB,GAAG2uB,QAAUjwB,EAAOsB,GAAG0uB,OAE9B,SAASE,IAAS9Z,EAAKoT,GACtB,EACCpT,GAAMA,EAAKoT,SACFpT,GAAwB,IAAjBA,EAAIvS,SAErB,OAAOuS,GAGRpW,EAAOgF,MACN8V,OAAQ,SAAUzX,GACjB,GAAIyX,GAASzX,EAAKe,UAClB,OAAO0W,IAA8B,KAApBA,EAAOjX,SAAkBiX,EAAS,MAEpDqV,QAAS,SAAU9sB,GAClB,MAAOrD,GAAOwpB,IAAKnmB,EAAM,eAE1B+sB,aAAc,SAAU/sB,EAAMqC,EAAG2qB,GAChC,MAAOrwB,GAAOwpB,IAAKnmB,EAAM,aAAcgtB,IAExCla,KAAM,SAAU9S,GACf,MAAO6sB,IAAS7sB,EAAM,gBAEvBosB,KAAM,SAAUpsB,GACf,MAAO6sB,IAAS7sB,EAAM,oBAEvBitB,QAAS,SAAUjtB,GAClB,MAAOrD,GAAOwpB,IAAKnmB,EAAM,gBAE1B0sB,QAAS,SAAU1sB,GAClB,MAAOrD,GAAOwpB,IAAKnmB,EAAM,oBAE1BktB,UAAW,SAAUltB,EAAMqC,EAAG2qB,GAC7B,MAAOrwB,GAAOwpB,IAAKnmB,EAAM,cAAegtB,IAEzCG,UAAW,SAAUntB,EAAMqC,EAAG2qB,GAC7B,MAAOrwB,GAAOwpB,IAAKnmB,EAAM,kBAAmBgtB,IAE7CI,SAAU,SAAUptB,GACnB,MAAOrD,GAAOkwB,SAAW7sB,EAAKe,gBAAmB0M,WAAYzN,IAE9DksB,SAAU,SAAUlsB,GACnB,MAAOrD,GAAOkwB,QAAS7sB,EAAKyN,aAE7B0e,SAAU,SAAUnsB,GACnB,MAAOrD,GAAOgK,SAAU3G,EAAM,UAC7BA,EAAKqtB,iBAAmBrtB,EAAKstB,cAAc9wB,SAC3CG,EAAO2D,SAAWN,EAAKsF,cAEvB,SAAUtC,EAAM/E,GAClBtB,EAAOsB,GAAI+E,GAAS,SAAUgqB,EAAOjvB,GACpC,GAAI0D,GAAM9E,EAAO6F,IAAKvC,KAAMhC,EAAI+uB,EAgBhC,OAdMnB,IAAOnrB,KAAMsC,KAClBjF,EAAWivB,GAGPjvB,GAAgC,gBAAbA,KACvB0D,EAAM9E,EAAOqf,OAAQje,EAAU0D,IAGhCA,EAAMxB,KAAKE,OAAS,IAAM8rB,GAAkBjpB,GAASrG,EAAOwN,OAAQ1I,GAAQA,EAEvExB,KAAKE,OAAS,GAAK2rB,GAAaprB,KAAMsC,KAC1CvB,EAAMA,EAAI8rB,WAGJttB,KAAKsB,UAAWE,MAIzB9E,EAAOiG,QACNoZ,OAAQ,SAAU5C,EAAM5X,EAAO+lB,GAK9B,MAJKA,KACJnO,EAAO,QAAUA,EAAO,KAGD,IAAjB5X,EAAMrB,OACZxD,EAAO0D,KAAK8jB,gBAAgB3iB,EAAM,GAAI4X,IAAU5X,EAAM,OACtD7E,EAAO0D,KAAKkb,QAAQnC,EAAM5X,IAG5B2kB,IAAK,SAAUnmB,EAAMmmB,EAAK6G,GACzB,GAAIlS,MACH/H,EAAM/S,EAAMmmB,EAEb,OAAQpT,GAAwB,IAAjBA,EAAIvS,WAAmBwsB,IAAU5wB,GAA8B,IAAjB2W,EAAIvS,WAAmB7D,EAAQoW,GAAMwZ,GAAIS,IAC/E,IAAjBja,EAAIvS,UACRsa,EAAQ1d,KAAM2V,GAEfA,EAAMA,EAAIoT,EAEX,OAAOrL,IAGR+R,QAAS,SAAUW,EAAGxtB,GACrB,GAAIytB,KAEJ,MAAQD,EAAGA,EAAIA,EAAEjI,YACI,IAAfiI,EAAEhtB,UAAkBgtB,IAAMxtB,GAC9BytB,EAAErwB,KAAMowB,EAIV,OAAOC,KAKT,SAASnB,IAAQ1Y,EAAU8Z,EAAWC,GAMrC,GAFAD,EAAYA,GAAa,EAEpB/wB,EAAOiE,WAAY8sB,GACvB,MAAO/wB,GAAO6K,KAAKoM,EAAU,SAAU5T,EAAMqC,GAC5C,GAAIqF,KAAWgmB,EAAUtsB,KAAMpB,EAAMqC,EAAGrC,EACxC,OAAO0H,KAAWimB,GAGb,IAAKD,EAAUltB,SACrB,MAAO7D,GAAO6K,KAAKoM,EAAU,SAAU5T,GACtC,MAASA,KAAS0tB,IAAgBC,GAG7B,IAA0B,gBAAdD,GAAyB,CAC3C,GAAIE,GAAWjxB,EAAO6K,KAAKoM,EAAU,SAAU5T,GAC9C,MAAyB,KAAlBA,EAAKQ,UAGb,IAAKurB,GAASrrB,KAAMgtB,GACnB,MAAO/wB,GAAOqf,OAAO0R,EAAWE,GAAWD,EAE3CD,GAAY/wB,EAAOqf,OAAQ0R,EAAWE,GAIxC,MAAOjxB,GAAO6K,KAAKoM,EAAU,SAAU5T,GACtC,MAASrD,GAAOwK,QAASnH,EAAM0tB,IAAe,IAAQC,IAGxD,QAASE,IAAoBrxB,GAC5B,GAAIiN,GAAOqkB,GAAUllB,MAAO,KAC3BmlB,EAAWvxB,EAAS4S,wBAErB,IAAK2e,EAAS5oB,cACb,MAAQsE,EAAKtJ,OACZ4tB,EAAS5oB,cACRsE,EAAKiI,MAIR,OAAOqc,GAGR,GAAID,IAAY,6JAEfE,GAAgB,6BAChBC,GAAmBtU,OAAO,OAASmU,GAAY,WAAY,KAC3DI,GAAqB,OACrBC,GAAY,0EACZC,GAAW,YACXC,GAAS,UACTC,GAAQ,YACRC,GAAe,0BACfC,GAA8B,wBAE9BC,GAAW,oCACXC,GAAc,4BACdC,GAAoB,cACpBC,GAAe,2CAGfC,IACCtZ,QAAU,EAAG,+BAAgC,aAC7CuZ,QAAU,EAAG,aAAc,eAC3BC,MAAQ,EAAG,QAAS,UACpBC,OAAS,EAAG,WAAY,aACxBC,OAAS,EAAG,UAAW,YACvBC,IAAM,EAAG,iBAAkB,oBAC3BC,KAAO,EAAG,mCAAoC,uBAC9CC,IAAM,EAAG,qBAAsB,yBAI/BxU,SAAUje,EAAO6P,QAAQmB,eAAkB,EAAG,GAAI,KAAS,EAAG,SAAU,WAEzE0hB,GAAexB,GAAoBrxB,GACnC8yB,GAAcD,GAAaliB,YAAa3Q,EAAS2I,cAAc,OAEhE0pB,IAAQU,SAAWV,GAAQtZ,OAC3BsZ,GAAQnhB,MAAQmhB,GAAQW,MAAQX,GAAQY,SAAWZ,GAAQa,QAAUb,GAAQI,MAC7EJ,GAAQc,GAAKd,GAAQO,GAErBzyB,EAAOsB,GAAG2E,QACTmE,KAAM,SAAUF,GACf,MAAOlK,GAAOmL,OAAQ7H,KAAM,SAAU4G,GACrC,MAAOA,KAAUzK,EAChBO,EAAOoK,KAAM9G,MACbA,KAAKqK,QAAQslB,QAAU3vB,KAAK,IAAMA,KAAK,GAAGQ,eAAiBjE,GAAWqzB,eAAgBhpB,KACrF,KAAMA,EAAO5E,UAAU9B,SAG3B2vB,QAAS,SAAUC,GAClB,GAAKpzB,EAAOiE,WAAYmvB,GACvB,MAAO9vB,MAAK0B,KAAK,SAASU,GACzB1F,EAAOsD,MAAM6vB,QAASC,EAAK3uB,KAAKnB,KAAMoC,KAIxC,IAAKpC,KAAK,GAAK,CAEd,GAAI+vB,GAAOrzB,EAAQozB,EAAM9vB,KAAK,GAAGQ,eAAgB0B,GAAG,GAAGe,OAAM,EAExDjD,MAAK,GAAGc,YACZivB,EAAKpM,aAAc3jB,KAAK,IAGzB+vB,EAAKxtB,IAAI,WACR,GAAIxC,GAAOC,IAEX,OAAQD,EAAKyN,YAA2C,IAA7BzN,EAAKyN,WAAWjN,SAC1CR,EAAOA,EAAKyN,UAGb,OAAOzN,KACL4vB,OAAQ3vB,MAGZ,MAAOA,OAGRgwB,UAAW,SAAUF,GACpB,MAAKpzB,GAAOiE,WAAYmvB,GAChB9vB,KAAK0B,KAAK,SAASU,GACzB1F,EAAOsD,MAAMgwB,UAAWF,EAAK3uB,KAAKnB,KAAMoC,MAInCpC,KAAK0B,KAAK,WAChB,GAAIoI,GAAOpN,EAAQsD,MAClBksB,EAAWpiB,EAAKoiB,UAEZA,GAAShsB,OACbgsB,EAAS2D,QAASC,GAGlBhmB,EAAK6lB,OAAQG,MAKhBC,KAAM,SAAUD,GACf,GAAInvB,GAAajE,EAAOiE,WAAYmvB,EAEpC,OAAO9vB,MAAK0B,KAAK,SAASU,GACzB1F,EAAQsD,MAAO6vB,QAASlvB,EAAamvB,EAAK3uB,KAAKnB,KAAMoC,GAAK0tB,MAI5DG,OAAQ,WACP,MAAOjwB,MAAKwX,SAAS9V,KAAK,WACnBhF,EAAOgK,SAAU1G,KAAM,SAC5BtD,EAAQsD,MAAOkwB,YAAalwB,KAAKqF,cAEhC7C,OAGJmtB,OAAQ,WACP,MAAO3vB,MAAKmwB,SAASnuB,WAAW,EAAM,SAAUjC,IACxB,IAAlBC,KAAKO,UAAoC,KAAlBP,KAAKO,UAAqC,IAAlBP,KAAKO,WACxDP,KAAKkN,YAAanN,MAKrBqwB,QAAS,WACR,MAAOpwB,MAAKmwB,SAASnuB,WAAW,EAAM,SAAUjC,IACxB,IAAlBC,KAAKO,UAAoC,KAAlBP,KAAKO,UAAqC,IAAlBP,KAAKO,WACxDP,KAAK2jB,aAAc5jB,EAAMC,KAAKwN,eAKjC6iB,OAAQ,WACP,MAAOrwB,MAAKmwB,SAAUnuB,WAAW,EAAO,SAAUjC,GAC5CC,KAAKc,YACTd,KAAKc,WAAW6iB,aAAc5jB,EAAMC,SAKvCswB,MAAO,WACN,MAAOtwB,MAAKmwB,SAAUnuB,WAAW,EAAO,SAAUjC,GAC5CC,KAAKc,YACTd,KAAKc,WAAW6iB,aAAc5jB,EAAMC,KAAKslB,gBAM5ClgB,OAAQ,SAAUtH,EAAUyyB,GAC3B,GAAIxwB,GACHqC,EAAI,CAEL,MAA4B,OAAnBrC,EAAOC,KAAKoC,IAAaA,MAC3BtE,GAAYpB,EAAOqf,OAAQje,GAAYiC,IAASG,OAAS,KACxDqwB,GAA8B,IAAlBxwB,EAAKQ,UACtB7D,EAAOmV,UAAW2e,GAAQzwB,IAGtBA,EAAKe,aACJyvB,GAAY7zB,EAAOyhB,SAAUpe,EAAKS,cAAeT,IACrD0wB,GAAeD,GAAQzwB,EAAM,WAE9BA,EAAKe,WAAWgQ,YAAa/Q,IAKhC,OAAOC,OAGRqK,MAAO,WACN,GAAItK,GACHqC,EAAI,CAEL,MAA4B,OAAnBrC,EAAOC,KAAKoC,IAAaA,IAAM,CAEhB,IAAlBrC,EAAKQ,UACT7D,EAAOmV,UAAW2e,GAAQzwB,GAAM,GAIjC,OAAQA,EAAKyN,WACZzN,EAAK+Q,YAAa/Q,EAAKyN,WAKnBzN,GAAKiD,SAAWtG,EAAOgK,SAAU3G,EAAM,YAC3CA,EAAKiD,QAAQ9C,OAAS,GAIxB,MAAOF,OAGRiD,MAAO,SAAUytB,EAAeC,GAI/B,MAHAD,GAAiC,MAAjBA,GAAwB,EAAQA,EAChDC,EAAyC,MAArBA,EAA4BD,EAAgBC,EAEzD3wB,KAAKuC,IAAK,WAChB,MAAO7F,GAAOuG,MAAOjD,KAAM0wB,EAAeC,MAI5Cb,KAAM,SAAUlpB,GACf,MAAOlK,GAAOmL,OAAQ7H,KAAM,SAAU4G,GACrC,GAAI7G,GAAOC,KAAK,OACfoC,EAAI,EACJkF,EAAItH,KAAKE,MAEV,IAAK0G,IAAUzK,EACd,MAAyB,KAAlB4D,EAAKQ,SACXR,EAAKkN,UAAUxH,QAASsoB,GAAe,IACvC5xB,CAIF,MAAsB,gBAAVyK,IAAuB0nB,GAAa7tB,KAAMmG,KACnDlK,EAAO6P,QAAQmB,eAAkBsgB,GAAavtB,KAAMmG,KACpDlK,EAAO6P,QAAQgB,mBAAsB0gB,GAAmBxtB,KAAMmG,IAC/DgoB,IAAWT,GAAShuB,KAAMyG,KAAY,GAAI,KAAM,GAAGD,gBAAkB,CAEtEC,EAAQA,EAAMnB,QAASyoB,GAAW,YAElC,KACC,KAAW5mB,EAAJlF,EAAOA,IAEbrC,EAAOC,KAAKoC,OACW,IAAlBrC,EAAKQ,WACT7D,EAAOmV,UAAW2e,GAAQzwB,GAAM,IAChCA,EAAKkN,UAAYrG,EAInB7G,GAAO,EAGN,MAAMyE,KAGJzE,GACJC,KAAKqK,QAAQslB,OAAQ/oB,IAEpB,KAAMA,EAAO5E,UAAU9B,SAG3BgwB,YAAa,SAAUtpB,GACtB,GAAIgqB,GAASl0B,EAAOiE,WAAYiG,EAQhC,OAJMgqB,IAA2B,gBAAVhqB,KACtBA,EAAQlK,EAAQkK,GAAQ0gB,IAAKtnB,MAAOT,UAG9BS,KAAKmwB,UAAYvpB,IAAS,EAAM,SAAU7G,GAChD,GAAI8S,GAAO7S,KAAKslB,YACf9N,EAASxX,KAAKc,UAEV0W,KACJ9a,EAAQsD,MAAOoF,SACfoS,EAAOmM,aAAc5jB,EAAM8S,OAK9BtT,OAAQ,SAAUzB,GACjB,MAAOkC,MAAKoF,OAAQtH,GAAU,IAG/BqyB,SAAU,SAAUvuB,EAAMivB,EAAOlvB,GAGhCC,EAAO5E,EAAY+E,SAAWH,EAE9B,IAAIK,GAAOuhB,EAAMsN,EAChB7rB,EAASoX,EAAK1P,EACdvK,EAAI,EACJkF,EAAItH,KAAKE,OACTmV,EAAMrV,KACN+wB,EAAWzpB,EAAI,EACfV,EAAQhF,EAAK,GACbjB,EAAajE,EAAOiE,WAAYiG,EAGjC,IAAKjG,KAAsB,GAAL2G,GAA2B,gBAAVV,IAAsBlK,EAAO6P,QAAQ8C,aAAemf,GAAS/tB,KAAMmG,GACzG,MAAO5G,MAAK0B,KAAK,SAAU0I,GAC1B,GAAIN,GAAOuL,EAAInT,GAAIkI,EACdzJ,KACJiB,EAAK,GAAKgF,EAAMzF,KAAMnB,KAAMoK,EAAOymB,EAAQ/mB,EAAKgmB,OAAS3zB,IAE1D2N,EAAKqmB,SAAUvuB,EAAMivB,EAAOlvB,IAI9B,IAAK2F,IACJqF,EAAWjQ,EAAOyI,cAAevD,EAAM5B,KAAM,GAAIQ,eAAe,EAAOR,MACvEiC,EAAQ0K,EAASa,WAEmB,IAA/Bb,EAAStH,WAAWnF,SACxByM,EAAW1K,GAGPA,GAAQ,CAOZ,IANA4uB,EAAQA,GAASn0B,EAAOgK,SAAUzE,EAAO,MACzCgD,EAAUvI,EAAO6F,IAAKiuB,GAAQ7jB,EAAU,UAAYqkB,IACpDF,EAAa7rB,EAAQ/E,OAIToH,EAAJlF,EAAOA,IACdohB,EAAO7W,EAEFvK,IAAM2uB,IACVvN,EAAO9mB,EAAOuG,MAAOugB,GAAM,GAAM,GAG5BsN,GACJp0B,EAAO2D,MAAO4E,EAASurB,GAAQhN,EAAM,YAIvC7hB,EAASR,KACR0vB,GAASn0B,EAAOgK,SAAU1G,KAAKoC,GAAI,SAClC6uB,GAAcjxB,KAAKoC,GAAI,SACvBpC,KAAKoC,GACNohB,EACAphB,EAIF,IAAK0uB,EAOJ,IANAzU,EAAMpX,EAASA,EAAQ/E,OAAS,GAAIM,cAGpC9D,EAAO6F,IAAK0C,EAASisB,IAGf9uB,EAAI,EAAO0uB,EAAJ1uB,EAAgBA,IAC5BohB,EAAOve,EAAS7C,GACXqsB,GAAYhuB,KAAM+iB,EAAKnkB,MAAQ,MAClC3C,EAAO0V,MAAOoR,EAAM,eAAkB9mB,EAAOyhB,SAAU9B,EAAKmH,KAExDA,EAAK5gB,IAETlG,EAAOy0B,MACNC,IAAK5N,EAAK5gB,IACVvD,KAAM,MACNgyB,SAAU,SACVprB,OAAO,EACP+R,QAAQ,EACRsZ,UAAU,IAGX50B,EAAO4J,YAAckd,EAAK1c,MAAQ0c,EAAKoC,aAAepC,EAAKvW,WAAa,IAAKxH,QAASkpB,GAAc,KAOxGhiB,GAAW1K,EAAQ,KAIrB,MAAOjC,QAIT,SAASixB,IAAclxB,EAAMkkB,GAC5B,MAAOlkB,GAAKqG,qBAAsB6d,GAAM,IAAMlkB,EAAKmN,YAAanN,EAAKS,cAAc0E,cAAe+e,IAInG,QAAS+M,IAAejxB,GACvB,GAAIa,GAAOb,EAAKiX,iBAAiB,OAEjC,OADAjX,GAAKV,MAASuB,GAAQA,EAAK2U,WAAc,IAAMxV,EAAKV,KAC7CU,EAER,QAASmxB,IAAenxB,GACvB,GAAID,GAAQ4uB,GAAkBvuB,KAAMJ,EAAKV,KAMzC,OALKS,GACJC,EAAKV,KAAOS,EAAM,GAElBC,EAAKiW,gBAAgB,QAEfjW,EAIR,QAAS0wB,IAAelvB,EAAOgwB,GAC9B,GAAIxxB,GACHqC,EAAI,CACL,MAA6B,OAApBrC,EAAOwB,EAAMa,IAAaA,IAClC1F,EAAO0V,MAAOrS,EAAM,cAAewxB,GAAe70B,EAAO0V,MAAOmf,EAAYnvB,GAAI,eAIlF,QAASovB,IAAgB5uB,EAAK6uB,GAE7B,GAAuB,IAAlBA,EAAKlxB,UAAmB7D,EAAOwV,QAAStP,GAA7C,CAIA,GAAIvD,GAAM+C,EAAGkF,EACZoqB,EAAUh1B,EAAO0V,MAAOxP,GACxB+uB,EAAUj1B,EAAO0V,MAAOqf,EAAMC,GAC9BvZ,EAASuZ,EAAQvZ,MAElB,IAAKA,EAAS,OACNwZ,GAAQ9Y,OACf8Y,EAAQxZ,SAER,KAAM9Y,IAAQ8Y,GACb,IAAM/V,EAAI,EAAGkF,EAAI6Q,EAAQ9Y,GAAOa,OAAYoH,EAAJlF,EAAOA,IAC9C1F,EAAOyC,MAAM6K,IAAKynB,EAAMpyB,EAAM8Y,EAAQ9Y,GAAQ+C,IAM5CuvB,EAAQ7sB,OACZ6sB,EAAQ7sB,KAAOpI,EAAOiG,UAAYgvB,EAAQ7sB,QAI5C,QAAS8sB,IAAoBhvB,EAAK6uB,GACjC,GAAI/qB,GAAUlC,EAAGM,CAGjB,IAAuB,IAAlB2sB,EAAKlxB,SAAV,CAOA,GAHAmG,EAAW+qB,EAAK/qB,SAASC,eAGnBjK,EAAO6P,QAAQkC,cAAgBgjB,EAAM/0B,EAAOkT,SAAY,CAC7D9K,EAAOpI,EAAO0V,MAAOqf,EAErB,KAAMjtB,IAAKM,GAAKqT,OACfzb,EAAOkd,YAAa6X,EAAMjtB,EAAGM,EAAK+T,OAInC4Y,GAAKzb,gBAAiBtZ,EAAOkT,SAIZ,WAAblJ,GAAyB+qB,EAAK3qB,OAASlE,EAAIkE,MAC/CkqB,GAAeS,GAAO3qB,KAAOlE,EAAIkE,KACjCoqB,GAAeO,IAIS,WAAb/qB,GACN+qB,EAAK3wB,aACT2wB,EAAKpjB,UAAYzL,EAAIyL,WAOjB3R,EAAO6P,QAAQ4B,YAAgBvL,EAAIqK,YAAcvQ,EAAOmB,KAAK4zB,EAAKxkB,aACtEwkB,EAAKxkB,UAAYrK,EAAIqK,YAGE,UAAbvG,GAAwB6nB,GAA4B9tB,KAAMmC,EAAIvD,OAKzEoyB,EAAKI,eAAiBJ,EAAK1iB,QAAUnM,EAAImM,QAIpC0iB,EAAK7qB,QAAUhE,EAAIgE,QACvB6qB,EAAK7qB,MAAQhE,EAAIgE,QAKM,WAAbF,EACX+qB,EAAKK,gBAAkBL,EAAKxjB,SAAWrL,EAAIkvB,iBAInB,UAAbprB,GAAqC,aAAbA,KACnC+qB,EAAKra,aAAexU,EAAIwU,eAI1B1a,EAAOgF,MACNqwB,SAAU,SACVC,UAAW,UACXrO,aAAc,SACdsO,YAAa,QACbC,WAAY,eACV,SAAUnvB,EAAMiZ,GAClBtf,EAAOsB,GAAI+E,GAAS,SAAUjF,GAC7B,GAAIyD,GACHa,EAAI,EACJZ,KACA2wB,EAASz1B,EAAQoB,GACjBqE,EAAOgwB,EAAOjyB,OAAS,CAExB,MAAaiC,GAALC,EAAWA,IAClBb,EAAQa,IAAMD,EAAOnC,KAAOA,KAAKiD,OAAM,GACvCvG,EAAQy1B,EAAO/vB,IAAM4Z,GAAYza,GAGjCrE,EAAU6E,MAAOP,EAAKD,EAAMH,MAG7B,OAAOpB,MAAKsB,UAAWE,KAIzB,SAASgvB,IAAQzyB,EAASkmB,GACzB,GAAI1iB,GAAOxB,EACVqC,EAAI,EACJgwB,QAAer0B,GAAQqI,uBAAyB9J,EAAoByB,EAAQqI,qBAAsB6d,GAAO,WACjGlmB,GAAQulB,mBAAqBhnB,EAAoByB,EAAQulB,iBAAkBW,GAAO,KACzF9nB,CAEF,KAAMi2B,EACL,IAAMA,KAAY7wB,EAAQxD,EAAQsH,YAActH,EAA8B,OAApBgC,EAAOwB,EAAMa,IAAaA,KAC7E6hB,GAAOvnB,EAAOgK,SAAU3G,EAAMkkB,GACnCmO,EAAMj1B,KAAM4C,GAEZrD,EAAO2D,MAAO+xB,EAAO5B,GAAQzwB,EAAMkkB,GAKtC,OAAOA,KAAQ9nB,GAAa8nB,GAAOvnB,EAAOgK,SAAU3I,EAASkmB,GAC5DvnB,EAAO2D,OAAStC,GAAWq0B,GAC3BA,EAIF,QAASC,IAAmBtyB,GACtBwuB,GAA4B9tB,KAAMV,EAAKV,QAC3CU,EAAK8xB,eAAiB9xB,EAAKgP,SAI7BrS,EAAOiG,QACNM,MAAO,SAAUlD,EAAM2wB,EAAeC,GACrC,GAAI2B,GAAc9O,EAAMvgB,EAAOb,EAAGmwB,EACjCC,EAAS91B,EAAOyhB,SAAUpe,EAAKS,cAAeT,EAW/C,IATKrD,EAAO6P,QAAQ4B,YAAczR,EAAOkZ,SAAS7V,KAAUiuB,GAAavtB,KAAM,IAAMV,EAAK2G,SAAW,KACpGzD,EAAQlD,EAAKqO,WAAW,IAIxBihB,GAAYpiB,UAAYlN,EAAKsO,UAC7BghB,GAAYve,YAAa7N,EAAQosB,GAAY7hB,eAGvC9Q,EAAO6P,QAAQkC,cAAiB/R,EAAO6P,QAAQyC,gBACjC,IAAlBjP,EAAKQ,UAAoC,KAAlBR,EAAKQ,UAAqB7D,EAAOkZ,SAAS7V,IAOnE,IAJAuyB,EAAe9B,GAAQvtB,GACvBsvB,EAAc/B,GAAQzwB,GAGhBqC,EAAI,EAA8B,OAA1BohB,EAAO+O,EAAYnwB,MAAeA,EAE1CkwB,EAAalwB,IACjBwvB,GAAoBpO,EAAM8O,EAAalwB,GAM1C,IAAKsuB,EACJ,GAAKC,EAIJ,IAHA4B,EAAcA,GAAe/B,GAAQzwB,GACrCuyB,EAAeA,GAAgB9B,GAAQvtB,GAEjCb,EAAI,EAA8B,OAA1BohB,EAAO+O,EAAYnwB,IAAaA,IAC7CovB,GAAgBhO,EAAM8O,EAAalwB,QAGpCovB,IAAgBzxB,EAAMkD,EAaxB,OARAqvB,GAAe9B,GAAQvtB,EAAO,UACzBqvB,EAAapyB,OAAS,GAC1BuwB,GAAe6B,GAAeE,GAAUhC,GAAQzwB,EAAM,WAGvDuyB,EAAeC,EAAc/O,EAAO,KAG7BvgB,GAGRkC,cAAe,SAAU5D,EAAOxD,EAASkH,EAASwtB,GACjD,GAAInwB,GAAGvC,EAAMoe,EACZtY,EAAKoe,EAAKxW,EAAOsiB,EACjBzoB,EAAI/F,EAAMrB,OAGVwyB,EAAO9E,GAAoB7vB,GAE3B40B,KACAvwB,EAAI,CAEL,MAAYkF,EAAJlF,EAAOA,IAGd,GAFArC,EAAOwB,EAAOa,GAETrC,GAAiB,IAATA,EAGZ,GAA6B,WAAxBrD,EAAO2C,KAAMU,GACjBrD,EAAO2D,MAAOsyB,EAAO5yB,EAAKQ,UAAaR,GAASA,OAG1C,IAAMsuB,GAAM5tB,KAAMV,GAIlB,CACN8F,EAAMA,GAAO6sB,EAAKxlB,YAAanP,EAAQmH,cAAc,QAGrD+e,GAAQkK,GAAShuB,KAAMJ,KAAW,GAAI,KAAM,GAAG4G,cAC/CopB,EAAOnB,GAAS3K,IAAS2K,GAAQjU,SAEjC9U,EAAIoH,UAAY8iB,EAAK,GAAKhwB,EAAK0F,QAASyoB,GAAW,aAAgB6B,EAAK,GAGxEztB,EAAIytB,EAAK,EACT,OAAQztB,IACPuD,EAAMA,EAAIyJ,SASX,KALM5S,EAAO6P,QAAQgB,mBAAqB0gB,GAAmBxtB,KAAMV,IAClE4yB,EAAMx1B,KAAMY,EAAQ6xB,eAAgB3B,GAAmB9tB,KAAMJ,GAAO,MAI/DrD,EAAO6P,QAAQkB,MAAQ,CAG5B1N,EAAe,UAARkkB,GAAoBmK,GAAO3tB,KAAMV,GAI3B,YAAZgwB,EAAK,IAAqB3B,GAAO3tB,KAAMV,GAEtC,EADA8F,EAJDA,EAAI2H,WAOLlL,EAAIvC,GAAQA,EAAKsF,WAAWnF,MAC5B,OAAQoC,IACF5F,EAAOgK,SAAW+G,EAAQ1N,EAAKsF,WAAW/C,GAAK,WAAcmL,EAAMpI,WAAWnF,QAClFH,EAAK+Q,YAAarD;CAKrB/Q,EAAO2D,MAAOsyB,EAAO9sB,EAAIR,YAGzBQ,EAAI+f,YAAc,EAGlB,OAAQ/f,EAAI2H,WACX3H,EAAIiL,YAAajL,EAAI2H,WAItB3H,GAAM6sB,EAAKpjB,cAtDXqjB,GAAMx1B,KAAMY,EAAQ6xB,eAAgB7vB,GA4DlC8F,IACJ6sB,EAAK5hB,YAAajL,GAKbnJ,EAAO6P,QAAQ6C,eACpB1S,EAAO6K,KAAMipB,GAAQmC,EAAO,SAAWN,IAGxCjwB,EAAI,CACJ,OAASrC,EAAO4yB,EAAOvwB,KAItB,KAAKqwB,GAAmD,KAAtC/1B,EAAOwK,QAASnH,EAAM0yB,MAIxCtU,EAAWzhB,EAAOyhB,SAAUpe,EAAKS,cAAeT,GAGhD8F,EAAM2qB,GAAQkC,EAAKxlB,YAAanN,GAAQ,UAGnCoe,GACJsS,GAAe5qB,GAIXZ,GAAU,CACd3C,EAAI,CACJ,OAASvC,EAAO8F,EAAKvD,KACfmsB,GAAYhuB,KAAMV,EAAKV,MAAQ,KACnC4F,EAAQ9H,KAAM4C,GAQlB,MAFA8F,GAAM,KAEC6sB,GAGR7gB,UAAW,SAAUtQ,EAAsB4P,GAC1C,GAAIpR,GAAMV,EAAM0B,EAAI+D,EACnB1C,EAAI,EACJiP,EAAc3U,EAAOkT,QACrB4B,EAAQ9U,EAAO8U,MACfhD,EAAgB9R,EAAO6P,QAAQiC,cAC/B8J,EAAU5b,EAAOyC,MAAMmZ,OAExB,MAA6B,OAApBvY,EAAOwB,EAAMa,IAAaA,IAElC,IAAK+O,GAAczU,EAAOyU,WAAYpR,MAErCgB,EAAKhB,EAAMsR,GACXvM,EAAO/D,GAAMyQ,EAAOzQ,IAER,CACX,GAAK+D,EAAKqT,OACT,IAAM9Y,IAAQyF,GAAKqT,OACbG,EAASjZ,GACb3C,EAAOyC,MAAMiG,OAAQrF,EAAMV,GAI3B3C,EAAOkd,YAAa7Z,EAAMV,EAAMyF,EAAK+T,OAMnCrH,GAAOzQ,WAEJyQ,GAAOzQ,GAKTyN,QACGzO,GAAMsR,SAEKtR,GAAKiW,kBAAoB1Z,EAC3CyD,EAAKiW,gBAAiB3E,GAGtBtR,EAAMsR,GAAgB,KAGvBvU,EAAgBK,KAAM4D,OAO5B,IAAI6xB,IAAQC,GAAWC,GACtBC,GAAS,kBACTC,GAAW,wBACXC,GAAY,4BAGZC,GAAe,4BACfC,GAAU,UACVC,GAAgB1Z,OAAQ,KAAOxb,EAAY,SAAU,KACrDm1B,GAAgB3Z,OAAQ,KAAOxb,EAAY,kBAAmB,KAC9Do1B,GAAc5Z,OAAQ,YAAcxb,EAAY,IAAK,KACrDq1B,IAAgBC,KAAM,SAEtBC,IAAYC,SAAU,WAAYC,WAAY,SAAUvjB,QAAS,SACjEwjB,IACCC,cAAe,EACfC,WAAY,KAGbC,IAAc,MAAO,QAAS,SAAU,QACxCC,IAAgB,SAAU,IAAK,MAAO,KAGvC,SAASC,IAAgB9mB,EAAOpK,GAG/B,GAAKA,IAAQoK,GACZ,MAAOpK,EAIR,IAAImxB,GAAUnxB,EAAK9C,OAAO,GAAGhB,cAAgB8D,EAAK1F,MAAM,GACvD82B,EAAWpxB,EACXX,EAAI4xB,GAAY9zB,MAEjB,OAAQkC,IAEP,GADAW,EAAOixB,GAAa5xB,GAAM8xB,EACrBnxB,IAAQoK,GACZ,MAAOpK,EAIT,OAAOoxB,GAGR,QAASC,IAAUr0B,EAAMs0B,GAIxB,MADAt0B,GAAOs0B,GAAMt0B,EAC4B,SAAlCrD,EAAO43B,IAAKv0B,EAAM,aAA2BrD,EAAOyhB,SAAUpe,EAAKS,cAAeT,GAG1F,QAASw0B,IAAU5gB,EAAU6gB,GAC5B,GAAIpkB,GAASrQ,EAAM00B,EAClBvoB,KACA9B,EAAQ,EACRlK,EAASyT,EAASzT,MAEnB,MAAgBA,EAARkK,EAAgBA,IACvBrK,EAAO4T,EAAUvJ,GACXrK,EAAKoN,QAIXjB,EAAQ9B,GAAU1N,EAAO0V,MAAOrS,EAAM,cACtCqQ,EAAUrQ,EAAKoN,MAAMiD,QAChBokB,GAGEtoB,EAAQ9B,IAAuB,SAAZgG,IACxBrQ,EAAKoN,MAAMiD,QAAU,IAMM,KAAvBrQ,EAAKoN,MAAMiD,SAAkBgkB,GAAUr0B,KAC3CmM,EAAQ9B,GAAU1N,EAAO0V,MAAOrS,EAAM,aAAc20B,GAAmB30B,EAAK2G,aAIvEwF,EAAQ9B,KACbqqB,EAASL,GAAUr0B,IAEdqQ,GAAuB,SAAZA,IAAuBqkB,IACtC/3B,EAAO0V,MAAOrS,EAAM,aAAc00B,EAASrkB,EAAU1T,EAAO43B,IAAKv0B,EAAM,aAQ3E,KAAMqK,EAAQ,EAAWlK,EAARkK,EAAgBA,IAChCrK,EAAO4T,EAAUvJ,GACXrK,EAAKoN,QAGLqnB,GAA+B,SAAvBz0B,EAAKoN,MAAMiD,SAA6C,KAAvBrQ,EAAKoN,MAAMiD,UACzDrQ,EAAKoN,MAAMiD,QAAUokB,EAAOtoB,EAAQ9B,IAAW,GAAK,QAItD,OAAOuJ,GAGRjX,EAAOsB,GAAG2E,QACT2xB,IAAK,SAAUvxB,EAAM6D,GACpB,MAAOlK,GAAOmL,OAAQ7H,KAAM,SAAUD,EAAMgD,EAAM6D,GACjD,GAAIvE,GAAKsyB,EACRpyB,KACAH,EAAI,CAEL,IAAK1F,EAAO0G,QAASL,GAAS,CAI7B,IAHA4xB,EAAS9B,GAAW9yB,GACpBsC,EAAMU,EAAK7C,OAECmC,EAAJD,EAASA,IAChBG,EAAKQ,EAAMX,IAAQ1F,EAAO43B,IAAKv0B,EAAMgD,EAAMX,IAAK,EAAOuyB,EAGxD,OAAOpyB,GAGR,MAAOqE,KAAUzK,EAChBO,EAAOyQ,MAAOpN,EAAMgD,EAAM6D,GAC1BlK,EAAO43B,IAAKv0B,EAAMgD,IACjBA,EAAM6D,EAAO5E,UAAU9B,OAAS,IAEpCs0B,KAAM,WACL,MAAOD,IAAUv0B,MAAM,IAExB40B,KAAM,WACL,MAAOL,IAAUv0B,OAElB60B,OAAQ,SAAUjqB,GACjB,GAAIkqB,GAAwB,iBAAVlqB,EAElB,OAAO5K,MAAK0B,KAAK,YACXozB,EAAOlqB,EAAQwpB,GAAUp0B,OAC7BtD,EAAQsD,MAAOw0B,OAEf93B,EAAQsD,MAAO40B,YAMnBl4B,EAAOiG,QAGNoyB,UACClnB,SACCzM,IAAK,SAAUrB,EAAMi1B,GACpB,GAAKA,EAAW,CAEf,GAAIxzB,GAAMsxB,GAAQ/yB,EAAM,UACxB,OAAe,KAARyB,EAAa,IAAMA,MAO9ByzB,WACCC,aAAe,EACfC,aAAe,EACfrB,YAAc,EACdsB,YAAc,EACdvnB,SAAW,EACXwnB,SAAW,EACXC,QAAU,EACVC,QAAU,EACV1kB,MAAQ,GAKT2kB,UAECC,QAAS/4B,EAAO6P,QAAQuB,SAAW,WAAa,cAIjDX,MAAO,SAAUpN,EAAMgD,EAAM6D,EAAO8uB,GAEnC,GAAM31B,GAA0B,IAAlBA,EAAKQ,UAAoC,IAAlBR,EAAKQ,UAAmBR,EAAKoN,MAAlE,CAKA,GAAI3L,GAAKnC,EAAMsT,EACdwhB,EAAWz3B,EAAO8J,UAAWzD,GAC7BoK,EAAQpN,EAAKoN,KASd,IAPApK,EAAOrG,EAAO84B,SAAUrB,KAAgBz3B,EAAO84B,SAAUrB,GAAaF,GAAgB9mB,EAAOgnB,IAI7FxhB,EAAQjW,EAAOq4B,SAAUhyB,IAAUrG,EAAOq4B,SAAUZ,GAG/CvtB,IAAUzK,EAsCd,MAAKwW,IAAS,OAASA,KAAUnR,EAAMmR,EAAMvR,IAAKrB,GAAM,EAAO21B,MAAav5B,EACpEqF,EAID2L,EAAOpK,EAhCd,IAVA1D,QAAcuH,GAGA,WAATvH,IAAsBmC,EAAM8xB,GAAQnzB,KAAMyG,MAC9CA,GAAUpF,EAAI,GAAK,GAAMA,EAAI,GAAK6C,WAAY3H,EAAO43B,IAAKv0B,EAAMgD,IAEhE1D,EAAO,YAIM,MAATuH,GAA0B,WAATvH,GAAqB+E,MAAOwC,KAKpC,WAATvH,GAAsB3C,EAAOu4B,UAAWd,KAC5CvtB,GAAS,MAKJlK,EAAO6P,QAAQuD,iBAA6B,KAAVlJ,GAA+C,IAA/B7D,EAAKxF,QAAQ,gBACpE4P,EAAOpK,GAAS,WAIX4P,GAAW,OAASA,KAAW/L,EAAQ+L,EAAM0C,IAAKtV,EAAM6G,EAAO8uB,MAAav5B,IAIjF,IACCgR,EAAOpK,GAAS6D,EACf,MAAMpC,OAcX8vB,IAAK,SAAUv0B,EAAMgD,EAAM2yB,EAAOf,GACjC,GAAItzB,GAAK8T,EAAKxC,EACbwhB,EAAWz3B,EAAO8J,UAAWzD,EAyB9B,OAtBAA,GAAOrG,EAAO84B,SAAUrB,KAAgBz3B,EAAO84B,SAAUrB,GAAaF,GAAgBl0B,EAAKoN,MAAOgnB,IAIlGxhB,EAAQjW,EAAOq4B,SAAUhyB,IAAUrG,EAAOq4B,SAAUZ,GAG/CxhB,GAAS,OAASA,KACtBwC,EAAMxC,EAAMvR,IAAKrB,GAAM,EAAM21B,IAIzBvgB,IAAQhZ,IACZgZ,EAAM2d,GAAQ/yB,EAAMgD,EAAM4xB,IAId,WAARxf,GAAoBpS,IAAQ6wB,MAChCze,EAAMye,GAAoB7wB,IAIZ,KAAV2yB,GAAgBA,GACpBr0B,EAAMgD,WAAY8Q,GACXugB,KAAU,GAAQh5B,EAAOyH,UAAW9C,GAAQA,GAAO,EAAI8T,GAExDA,GAIRwgB,KAAM,SAAU51B,EAAMiD,EAASrB,EAAUC,GACxC,GAAIJ,GAAKuB,EACR8f,IAGD,KAAM9f,IAAQC,GACb6f,EAAK9f,GAAShD,EAAKoN,MAAOpK,GAC1BhD,EAAKoN,MAAOpK,GAASC,EAASD,EAG/BvB,GAAMG,EAASI,MAAOhC,EAAM6B,MAG5B,KAAMmB,IAAQC,GACbjD,EAAKoN,MAAOpK,GAAS8f,EAAK9f,EAG3B,OAAOvB,MAMJtF,EAAOwU,kBACXmiB,GAAY,SAAU9yB,GACrB,MAAO7D,GAAOwU,iBAAkB3Q,EAAM,OAGvC+yB,GAAS,SAAU/yB,EAAMgD,EAAM6yB,GAC9B,GAAIjlB,GAAOklB,EAAUC,EACpBd,EAAWY,GAAa/C,GAAW9yB,GAGnCyB,EAAMwzB,EAAWA,EAASe,iBAAkBhzB,IAAUiyB,EAAUjyB,GAAS5G,EACzEgR,EAAQpN,EAAKoN,KA8Bd,OA5BK6nB,KAES,KAARxzB,GAAe9E,EAAOyhB,SAAUpe,EAAKS,cAAeT,KACxDyB,EAAM9E,EAAOyQ,MAAOpN,EAAMgD,IAOtBswB,GAAU5yB,KAAMe,IAAS2xB,GAAQ1yB,KAAMsC,KAG3C4N,EAAQxD,EAAMwD,MACdklB,EAAW1oB,EAAM0oB,SACjBC,EAAW3oB,EAAM2oB,SAGjB3oB,EAAM0oB,SAAW1oB,EAAM2oB,SAAW3oB,EAAMwD,MAAQnP,EAChDA,EAAMwzB,EAASrkB,MAGfxD,EAAMwD,MAAQA,EACdxD,EAAM0oB,SAAWA,EACjB1oB,EAAM2oB,SAAWA,IAIZt0B,IAEGjF,EAAS4J,gBAAgB6vB,eACpCnD,GAAY,SAAU9yB,GACrB,MAAOA,GAAKi2B,cAGblD,GAAS,SAAU/yB,EAAMgD,EAAM6yB,GAC9B,GAAIK,GAAMC,EAAIC,EACbnB,EAAWY,GAAa/C,GAAW9yB,GACnCyB,EAAMwzB,EAAWA,EAAUjyB,GAAS5G,EACpCgR,EAAQpN,EAAKoN,KAoCd,OAhCY,OAAP3L,GAAe2L,GAASA,EAAOpK,KACnCvB,EAAM2L,EAAOpK,IAUTswB,GAAU5yB,KAAMe,KAAUyxB,GAAUxyB,KAAMsC,KAG9CkzB,EAAO9oB,EAAM8oB,KACbC,EAAKn2B,EAAKq2B,aACVD,EAASD,GAAMA,EAAGD,KAGbE,IACJD,EAAGD,KAAOl2B,EAAKi2B,aAAaC,MAE7B9oB,EAAM8oB,KAAgB,aAATlzB,EAAsB,MAAQvB,EAC3CA,EAAM2L,EAAMkpB,UAAY,KAGxBlpB,EAAM8oB,KAAOA,EACRE,IACJD,EAAGD,KAAOE,IAIG,KAAR30B,EAAa,OAASA,GAI/B,SAAS80B,IAAmBv2B,EAAM6G,EAAO2vB,GACxC,GAAIjb,GAAU8X,GAAUjzB,KAAMyG,EAC9B,OAAO0U,GAENnU,KAAKC,IAAK,EAAGkU,EAAS,IAAQib,GAAY,KAAUjb,EAAS,IAAO,MACpE1U,EAGF,QAAS4vB,IAAsBz2B,EAAMgD,EAAM2yB,EAAOe,EAAa9B,GAC9D,GAAIvyB,GAAIszB,KAAYe,EAAc,SAAW,WAE5C,EAES,UAAT1zB,EAAmB,EAAI,EAEvBoS,EAAM,CAEP,MAAY,EAAJ/S,EAAOA,GAAK,EAEJ,WAAVszB,IACJvgB,GAAOzY,EAAO43B,IAAKv0B,EAAM21B,EAAQ3B,GAAW3xB,IAAK,EAAMuyB,IAGnD8B,GAEW,YAAVf,IACJvgB,GAAOzY,EAAO43B,IAAKv0B,EAAM,UAAYg0B,GAAW3xB,IAAK,EAAMuyB,IAI7C,WAAVe,IACJvgB,GAAOzY,EAAO43B,IAAKv0B,EAAM,SAAWg0B,GAAW3xB,GAAM,SAAS,EAAMuyB,MAIrExf,GAAOzY,EAAO43B,IAAKv0B,EAAM,UAAYg0B,GAAW3xB,IAAK,EAAMuyB,GAG5C,YAAVe,IACJvgB,GAAOzY,EAAO43B,IAAKv0B,EAAM,SAAWg0B,GAAW3xB,GAAM,SAAS,EAAMuyB,IAKvE,OAAOxf,GAGR,QAASuhB,IAAkB32B,EAAMgD,EAAM2yB,GAGtC,GAAIiB,IAAmB,EACtBxhB,EAAe,UAATpS,EAAmBhD,EAAKwQ,YAAcxQ,EAAKoQ,aACjDwkB,EAAS9B,GAAW9yB,GACpB02B,EAAc/5B,EAAO6P,QAAQ+D,WAAgE,eAAnD5T,EAAO43B,IAAKv0B,EAAM,aAAa,EAAO40B,EAKjF,IAAY,GAAPxf,GAAmB,MAAPA,EAAc,CAQ9B,GANAA,EAAM2d,GAAQ/yB,EAAMgD,EAAM4xB,IACf,EAANxf,GAAkB,MAAPA,KACfA,EAAMpV,EAAKoN,MAAOpK,IAIdswB,GAAU5yB,KAAK0U,GACnB,MAAOA,EAKRwhB,GAAmBF,IAAiB/5B,EAAO6P,QAAQsC,mBAAqBsG,IAAQpV,EAAKoN,MAAOpK,IAG5FoS,EAAM9Q,WAAY8Q,IAAS,EAI5B,MAASA,GACRqhB,GACCz2B,EACAgD,EACA2yB,IAAWe,EAAc,SAAW,WACpCE,EACAhC,GAEE,KAIL,QAASD,IAAoBhuB,GAC5B,GAAI2V,GAAM9f,EACT6T,EAAUmjB,GAAa7sB,EA0BxB,OAxBM0J,KACLA,EAAUwmB,GAAelwB,EAAU2V,GAGlB,SAAZjM,GAAuBA,IAE3BwiB,IAAWA,IACVl2B,EAAO,kDACN43B,IAAK,UAAW,6BAChBvC,SAAU1V,EAAIlW,iBAGhBkW,GAAQuW,GAAO,GAAGvF,eAAiBuF,GAAO,GAAGxF,iBAAkB7wB,SAC/D8f,EAAIwa,MAAM,+BACVxa,EAAIya,QAEJ1mB,EAAUwmB,GAAelwB,EAAU2V,GACnCuW,GAAOrzB,UAIRg0B,GAAa7sB,GAAa0J,GAGpBA,EAIR,QAASwmB,IAAe7zB,EAAMsZ,GAC7B,GAAItc,GAAOrD,EAAQ2f,EAAInX,cAAenC,IAASgvB,SAAU1V,EAAI1Y,MAC5DyM,EAAU1T,EAAO43B,IAAKv0B,EAAK,GAAI,UAEhC,OADAA,GAAKqF,SACEgL,EAGR1T,EAAOgF,MAAO,SAAU,SAAW,SAAUU,EAAGW,GAC/CrG,EAAOq4B,SAAUhyB,IAChB3B,IAAK,SAAUrB,EAAMi1B,EAAUU,GAC9B,MAAKV,GAGwB,IAArBj1B,EAAKwQ,aAAqB2iB,GAAazyB,KAAM/D,EAAO43B,IAAKv0B,EAAM,YACrErD,EAAOi5B,KAAM51B,EAAM0zB,GAAS,WAC3B,MAAOiD,IAAkB32B,EAAMgD,EAAM2yB,KAEtCgB,GAAkB32B,EAAMgD,EAAM2yB,GAPhC,GAWDrgB,IAAK,SAAUtV,EAAM6G,EAAO8uB,GAC3B,GAAIf,GAASe,GAAS7C,GAAW9yB,EACjC,OAAOu2B,IAAmBv2B,EAAM6G,EAAO8uB,EACtCc,GACCz2B,EACAgD,EACA2yB,EACAh5B,EAAO6P,QAAQ+D,WAAgE,eAAnD5T,EAAO43B,IAAKv0B,EAAM,aAAa,EAAO40B,GAClEA,GACG,OAMFj4B,EAAO6P,QAAQsB,UACpBnR,EAAOq4B,SAASlnB,SACfzM,IAAK,SAAUrB,EAAMi1B,GAEpB,MAAOhC,IAASvyB,MAAOu0B,GAAYj1B,EAAKi2B,aAAej2B,EAAKi2B,aAAaja,OAAShc,EAAKoN,MAAM4O,SAAW,IACrG,IAAO1X,WAAYqV,OAAOqd,IAAS,GACrC/B,EAAW,IAAM,IAGnB3f,IAAK,SAAUtV,EAAM6G,GACpB,GAAIuG,GAAQpN,EAAKoN,MAChB6oB,EAAej2B,EAAKi2B,aACpBnoB,EAAUnR,EAAOyH,UAAWyC,GAAU,iBAA2B,IAARA,EAAc,IAAM,GAC7EmV,EAASia,GAAgBA,EAAaja,QAAU5O,EAAM4O,QAAU,EAIjE5O,GAAM0D,KAAO,GAINjK,GAAS,GAAe,KAAVA,IAC6B,KAAhDlK,EAAOmB,KAAMke,EAAOtW,QAASstB,GAAQ,MACrC5lB,EAAM6I,kBAKP7I,EAAM6I,gBAAiB,UAGR,KAAVpP,GAAgBovB,IAAiBA,EAAaja,UAMpD5O,EAAM4O,OAASgX,GAAOtyB,KAAMsb,GAC3BA,EAAOtW,QAASstB,GAAQllB,GACxBkO,EAAS,IAAMlO,MAOnBnR,EAAO,WACAA,EAAO6P,QAAQqC,sBACpBlS,EAAOq4B,SAASnkB,aACfxP,IAAK,SAAUrB,EAAMi1B,GACpB,MAAKA,GAGGt4B,EAAOi5B,KAAM51B,GAAQqQ,QAAW,gBACtC0iB,IAAU/yB,EAAM,gBAJlB,MAaGrD,EAAO6P,QAAQuC,eAAiBpS,EAAOsB,GAAG01B,UAC/Ch3B,EAAOgF,MAAQ,MAAO,QAAU,SAAUU,EAAGkS,GAC5C5X,EAAOq4B,SAAUzgB,IAChBlT,IAAK,SAAUrB,EAAMi1B,GACpB,MAAKA,IACJA,EAAWlC,GAAQ/yB,EAAMuU,GAElB+e,GAAU5yB,KAAMu0B,GACtBt4B,EAAQqD,GAAO2zB,WAAYpf,GAAS,KACpC0gB,GALF,QAcAt4B,EAAOyc,MAAQzc,EAAOyc,KAAKwS,UAC/BjvB,EAAOyc,KAAKwS,QAAQ8I,OAAS,SAAU10B,GAGtC,MAA2B,IAApBA,EAAKwQ,aAAyC,GAArBxQ,EAAKoQ,eAClCzT,EAAO6P,QAAQ8D,uBAAmG,UAAxEtQ,EAAKoN,OAASpN,EAAKoN,MAAMiD,SAAY1T,EAAO43B,IAAKv0B,EAAM,aAGrGrD,EAAOyc,KAAKwS,QAAQqL,QAAU,SAAUj3B,GACvC,OAAQrD,EAAOyc,KAAKwS,QAAQ8I,OAAQ10B,KAKtCrD,EAAOgF,MACNu1B,OAAQ,GACRC,QAAS,GACTC,OAAQ,SACN,SAAUC,EAAQC,GACpB36B,EAAOq4B,SAAUqC,EAASC,IACzBC,OAAQ,SAAU1wB,GACjB,GAAIxE,GAAI,EACPm1B,KAGAC,EAAyB,gBAAV5wB,GAAqBA,EAAM+B,MAAM,MAAS/B,EAE1D,MAAY,EAAJxE,EAAOA,IACdm1B,EAAUH,EAASrD,GAAW3xB,GAAMi1B,GACnCG,EAAOp1B,IAAOo1B,EAAOp1B,EAAI,IAAOo1B,EAAO,EAGzC,OAAOD,KAIHpE,GAAQ1yB,KAAM22B,KACnB16B,EAAOq4B,SAAUqC,EAASC,GAAShiB,IAAMihB,KAG3C,IAAImB,IAAM,OACTC,GAAW,QACXC,GAAQ,SACRC,GAAkB,wCAClBC,GAAe,oCAEhBn7B,GAAOsB,GAAG2E,QACTm1B,UAAW,WACV,MAAOp7B,GAAOqyB,MAAO/uB,KAAK+3B,mBAE3BA,eAAgB,WACf,MAAO/3B,MAAKuC,IAAI,WAEf,GAAIoR,GAAWjX,EAAO4X,KAAMtU,KAAM,WAClC,OAAO2T,GAAWjX,EAAOsE,UAAW2S,GAAa3T,OAEjD+b,OAAO,WACP,GAAI1c,GAAOW,KAAKX,IAEhB,OAAOW,MAAK+C,OAASrG,EAAQsD,MAAOssB,GAAI,cACvCuL,GAAap3B,KAAMT,KAAK0G,YAAekxB,GAAgBn3B,KAAMpB,KAC3DW,KAAK+O,UAAYwf,GAA4B9tB,KAAMpB,MAEtDkD,IAAI,SAAUH,EAAGrC,GACjB,GAAIoV,GAAMzY,EAAQsD,MAAOmV,KAEzB,OAAc,OAAPA,EACN,KACAzY,EAAO0G,QAAS+R,GACfzY,EAAO6F,IAAK4S,EAAK,SAAUA,GAC1B,OAASpS,KAAMhD,EAAKgD,KAAM6D,MAAOuO,EAAI1P,QAASkyB,GAAO,YAEpD50B,KAAMhD,EAAKgD,KAAM6D,MAAOuO,EAAI1P,QAASkyB,GAAO,WAC9Cv2B,SAML1E,EAAOqyB,MAAQ,SAAUviB,EAAGwrB,GAC3B,GAAIZ,GACHa,KACAjuB,EAAM,SAAUvF,EAAKmC,GAEpBA,EAAQlK,EAAOiE,WAAYiG,GAAUA,IAAqB,MAATA,EAAgB,GAAKA,EACtEqxB,EAAGA,EAAE/3B,QAAWg4B,mBAAoBzzB,GAAQ,IAAMyzB,mBAAoBtxB,GASxE,IALKoxB,IAAgB77B,IACpB67B,EAAct7B,EAAOy7B,cAAgBz7B,EAAOy7B,aAAaH,aAIrDt7B,EAAO0G,QAASoJ,IAASA,EAAE5M,SAAWlD,EAAOgE,cAAe8L,GAEhE9P,EAAOgF,KAAM8K,EAAG,WACfxC,EAAKhK,KAAK+C,KAAM/C,KAAK4G,aAMtB,KAAMwwB,IAAU5qB,GACf4rB,GAAahB,EAAQ5qB,EAAG4qB,GAAUY,EAAahuB,EAKjD,OAAOiuB,GAAE5e,KAAM,KAAM5T,QAASgyB,GAAK,KAGpC,SAASW,IAAahB,EAAQpzB,EAAKg0B,EAAahuB,GAC/C,GAAIjH,EAEJ,IAAKrG,EAAO0G,QAASY,GAEpBtH,EAAOgF,KAAMsC,EAAK,SAAU5B,EAAGi2B,GACzBL,GAAeN,GAASj3B,KAAM22B,GAElCptB,EAAKotB,EAAQiB,GAIbD,GAAahB,EAAS,KAAqB,gBAANiB,GAAiBj2B,EAAI,IAAO,IAAKi2B,EAAGL,EAAahuB,SAIlF,IAAMguB,GAAsC,WAAvBt7B,EAAO2C,KAAM2E,GAQxCgG,EAAKotB,EAAQpzB,OANb,KAAMjB,IAAQiB,GACbo0B,GAAahB,EAAS,IAAMr0B,EAAO,IAAKiB,EAAKjB,GAAQi1B,EAAahuB,GAQrEtN,EAAOgF,KAAM,0MAEqDiH,MAAM,KAAM,SAAUvG,EAAGW,GAG1FrG,EAAOsB,GAAI+E,GAAS,SAAU+B,EAAM9G,GACnC,MAAOgE,WAAU9B,OAAS,EACzBF,KAAK4e,GAAI7b,EAAM,KAAM+B,EAAM9G,GAC3BgC,KAAK8D,QAASf,MAIjBrG,EAAOsB,GAAGs6B,MAAQ,SAAUC,EAAQC,GACnC,MAAOx4B,MAAK+d,WAAYwa,GAASva,WAAYwa,GAASD,GAEvD,IAECE,IACAC,GACAC,GAAaj8B,EAAOwL,MAEpB0wB,GAAc,KACdC,GAAQ,OACRC,GAAM,gBACNC,GAAW,gCAEXC,GAAiB,4DACjBC,GAAa,iBACbC,GAAY,QACZC,GAAO,8CAGPC,GAAQ18B,EAAOsB,GAAGif,KAWlBoc,MAOAC,MAGAC,GAAW,KAAKt8B,OAAO,IAIxB,KACCy7B,GAAel8B,EAAS0a,KACvB,MAAO1S,IAGRk0B,GAAen8B,EAAS2I,cAAe,KACvCwzB,GAAaxhB,KAAO,GACpBwhB,GAAeA,GAAaxhB,KAI7BuhB,GAAeU,GAAKh5B,KAAMu4B,GAAa/xB,kBAGvC,SAAS6yB,IAA6BC,GAGrC,MAAO,UAAUC,EAAoBhvB,GAED,gBAAvBgvB,KACXhvB,EAAOgvB,EACPA,EAAqB,IAGtB,IAAIrI,GACHjvB,EAAI,EACJu3B,EAAYD,EAAmB/yB,cAAc7G,MAAO1B,MAErD,IAAK1B,EAAOiE,WAAY+J,GAEvB,MAAS2mB,EAAWsI,EAAUv3B,KAER,MAAhBivB,EAAS,IACbA,EAAWA,EAASh0B,MAAO,IAAO,KACjCo8B,EAAWpI,GAAaoI,EAAWpI,QAAkBte,QAASrI,KAI9D+uB,EAAWpI,GAAaoI,EAAWpI,QAAkBl0B,KAAMuN,IAQjE,QAASkvB,IAA+BH,EAAWz2B,EAAS62B,EAAiBC,GAE5E,GAAIC,MACHC,EAAqBP,IAAcH,EAEpC,SAASW,GAAS5I,GACjB,GAAIpjB,EAYJ,OAXA8rB,GAAW1I,IAAa,EACxB30B,EAAOgF,KAAM+3B,EAAWpI,OAAkB,SAAUtoB,EAAGmxB,GACtD,GAAIC,GAAsBD,EAAoBl3B,EAAS62B,EAAiBC,EACxE,OAAmC,gBAAxBK,IAAqCH,GAAqBD,EAAWI,GAIpEH,IACD/rB,EAAWksB,GADf,GAHNn3B,EAAQ22B,UAAU5mB,QAASonB,GAC3BF,EAASE,IACF,KAKFlsB,EAGR,MAAOgsB,GAASj3B,EAAQ22B,UAAW,MAAUI,EAAW,MAASE,EAAS,KAM3E,QAASG,IAAYl3B,EAAQN,GAC5B,GAAIO,GAAMsB,EACT41B,EAAc39B,EAAOy7B,aAAakC,eAEnC,KAAM51B,IAAO7B,GACPA,EAAK6B,KAAUtI,KACjBk+B,EAAa51B,GAAQvB,EAAWC,IAASA,OAAgBsB,GAAQ7B,EAAK6B,GAO1E,OAJKtB,IACJzG,EAAOiG,QAAQ,EAAMO,EAAQC,GAGvBD,EAGRxG,EAAOsB,GAAGif,KAAO,SAAUmU,EAAKkJ,EAAQ34B,GACvC,GAAoB,gBAARyvB,IAAoBgI,GAC/B,MAAOA,IAAMr3B,MAAO/B,KAAMgC,UAG3B,IAAIlE,GAAUy8B,EAAUl7B,EACvByK,EAAO9J,KACP+D,EAAMqtB,EAAI7zB,QAAQ,IA+CnB,OA7CKwG,IAAO,IACXjG,EAAWszB,EAAI/zB,MAAO0G,EAAKqtB,EAAIlxB,QAC/BkxB,EAAMA,EAAI/zB,MAAO,EAAG0G,IAIhBrH,EAAOiE,WAAY25B,IAGvB34B,EAAW24B,EACXA,EAASn+B,GAGEm+B,GAA4B,gBAAXA,KAC5Bj7B,EAAO,QAIHyK,EAAK5J,OAAS,GAClBxD,EAAOy0B,MACNC,IAAKA,EAGL/xB,KAAMA,EACNgyB,SAAU,OACVvsB,KAAMw1B,IACJx4B,KAAK,SAAU04B,GAGjBD,EAAWv4B,UAEX8H,EAAKgmB,KAAMhyB,EAIVpB,EAAO,SAASizB,OAAQjzB,EAAO4D,UAAWk6B,IAAiBp6B,KAAMtC,GAGjE08B,KAECC,SAAU94B,GAAY,SAAUm4B,EAAOY,GACzC5wB,EAAKpI,KAAMC,EAAU44B,IAAcT,EAAMU,aAAcE,EAAQZ,MAI1D95B,MAIRtD,EAAOgF,MAAQ,YAAa,WAAY,eAAgB,YAAa,cAAe,YAAc,SAAUU,EAAG/C,GAC9G3C,EAAOsB,GAAIqB,GAAS,SAAUrB,GAC7B,MAAOgC,MAAK4e,GAAIvf,EAAMrB,MAIxBtB,EAAOgF,MAAQ,MAAO,QAAU,SAAUU,EAAGu4B,GAC5Cj+B,EAAQi+B,GAAW,SAAUvJ,EAAKtsB,EAAMnD,EAAUtC,GAQjD,MANK3C,GAAOiE,WAAYmE,KACvBzF,EAAOA,GAAQsC,EACfA,EAAWmD,EACXA,EAAO3I,GAGDO,EAAOy0B,MACbC,IAAKA,EACL/xB,KAAMs7B,EACNtJ,SAAUhyB,EACVyF,KAAMA,EACN81B,QAASj5B,OAKZjF,EAAOiG,QAGNk4B,OAAQ,EAGRC,gBACAC,QAEA5C,cACC/G,IAAKsH,GACLr5B,KAAM,MACN27B,QAAShC,GAAev4B,KAAMg4B,GAAc,IAC5CzgB,QAAQ,EACRijB,aAAa,EACbh1B,OAAO,EACPi1B,YAAa,mDAabC,SACCC,IAAK7B,GACLzyB,KAAM,aACNgpB,KAAM,YACNlqB,IAAK,4BACLy1B,KAAM,qCAGPnP,UACCtmB,IAAK,MACLkqB,KAAM,OACNuL,KAAM,QAGPC,gBACC11B,IAAK,cACLkB,KAAM,gBAKPy0B,YAGCC,SAAUt/B,EAAOqI,OAGjBk3B,aAAa,EAGbC,YAAah/B,EAAO4I,UAGpBq2B,WAAYj/B,EAAOiJ,UAOpB00B,aACCjJ,KAAK,EACLrzB,SAAS,IAOX69B,UAAW,SAAU14B,EAAQ24B,GAC5B,MAAOA,GAGNzB,GAAYA,GAAYl3B,EAAQxG,EAAOy7B,cAAgB0D,GAGvDzB,GAAY19B,EAAOy7B,aAAcj1B,IAGnC44B,cAAetC,GAA6BH,IAC5C0C,cAAevC,GAA6BF,IAG5CnI,KAAM,SAAUC,EAAKpuB,GAGA,gBAARouB,KACXpuB,EAAUouB,EACVA,EAAMj1B,GAIP6G,EAAUA,KAEV,IACCw0B,GAEAp1B,EAEA45B,EAEAC,EAEAC,EAGAC,EAEAC,EAEAC,EAEApE,EAAIv7B,EAAOk/B,aAAe54B,GAE1Bs5B,EAAkBrE,EAAEl6B,SAAWk6B,EAE/BsE,EAAqBtE,EAAEl6B,UAAau+B,EAAgB/7B,UAAY+7B,EAAgB18B,QAC/ElD,EAAQ4/B,GACR5/B,EAAOyC,MAER2L,EAAWpO,EAAO2L,WAClBm0B,EAAmB9/B,EAAOuM,UAAU,eAEpCwzB,EAAaxE,EAAEwE,eAEfC,KACAC,KAEA/xB,EAAQ,EAERgyB,EAAW,WAEX9C,GACCx6B,WAAY,EAGZu9B,kBAAmB,SAAUp4B,GAC5B,GAAI3E,EACJ,IAAe,IAAV8K,EAAc,CAClB,IAAMyxB,EAAkB,CACvBA,IACA,OAASv8B,EAAQi5B,GAAS54B,KAAM87B,GAC/BI,EAAiBv8B,EAAM,GAAG6G,eAAkB7G,EAAO,GAGrDA,EAAQu8B,EAAiB53B,EAAIkC,eAE9B,MAAgB,OAAT7G,EAAgB,KAAOA,GAI/Bg9B,sBAAuB,WACtB,MAAiB,KAAVlyB,EAAcqxB,EAAwB,MAI9Cc,iBAAkB,SAAUh6B,EAAM6D,GACjC,GAAIo2B,GAAQj6B,EAAK4D,aAKjB,OAJMiE,KACL7H,EAAO45B,EAAqBK,GAAUL,EAAqBK,IAAWj6B,EACtE25B,EAAgB35B,GAAS6D,GAEnB5G,MAIRi9B,iBAAkB,SAAU59B,GAI3B,MAHMuL,KACLqtB,EAAEiF,SAAW79B,GAEPW,MAIRy8B,WAAY,SAAUl6B,GACrB,GAAI46B,EACJ,IAAK56B,EACJ,GAAa,EAARqI,EACJ,IAAMuyB,IAAQ56B,GAEbk6B,EAAYU,IAAWV,EAAYU,GAAQ56B,EAAK46B,QAIjDrD,GAAMjvB,OAAQtI,EAAKu3B,EAAMY,QAG3B,OAAO16B,OAIRo9B,MAAO,SAAUC,GAChB,GAAIC,GAAYD,GAAcT,CAK9B,OAJKR,IACJA,EAAUgB,MAAOE,GAElBx7B,EAAM,EAAGw7B,GACFt9B,MAwCV,IAnCA8K,EAASjJ,QAASi4B,GAAQW,SAAW+B,EAAiBxyB,IACtD8vB,EAAMc,QAAUd,EAAMh4B,KACtBg4B,EAAMn1B,MAAQm1B,EAAM/uB,KAMpBktB,EAAE7G,MAAUA,GAAO6G,EAAE7G,KAAOsH,IAAiB,IAAKjzB,QAASozB,GAAO,IAAKpzB,QAASyzB,GAAWT,GAAc,GAAM,MAG/GR,EAAE54B,KAAO2D,EAAQ23B,QAAU33B,EAAQ3D,MAAQ44B,EAAE0C,QAAU1C,EAAE54B,KAGzD44B,EAAE0B,UAAYj9B,EAAOmB,KAAMo6B,EAAE5G,UAAY,KAAM1qB,cAAc7G,MAAO1B,KAAqB,IAGnE,MAAjB65B,EAAEsF,cACN/F,EAAQ2B,GAAKh5B,KAAM83B,EAAE7G,IAAIzqB,eACzBsxB,EAAEsF,eAAkB/F,GACjBA,EAAO,KAAQiB,GAAc,IAAOjB,EAAO,KAAQiB,GAAc,KAChEjB,EAAO,KAAwB,UAAfA,EAAO,GAAkB,GAAK,QAC7CiB,GAAc,KAA+B,UAAtBA,GAAc,GAAkB,GAAK,QAK7DR,EAAEnzB,MAAQmzB,EAAEgD,aAAiC,gBAAXhD,GAAEnzB,OACxCmzB,EAAEnzB,KAAOpI,EAAOqyB,MAAOkJ,EAAEnzB,KAAMmzB,EAAED,cAIlC4B,GAA+BP,GAAYpB,EAAGj1B,EAAS82B,GAGxC,IAAVlvB,EACJ,MAAOkvB,EAIRqC,GAAclE,EAAEjgB,OAGXmkB,GAAmC,IAApBz/B,EAAOm+B,UAC1Bn+B,EAAOyC,MAAM2E,QAAQ,aAItBm0B,EAAE54B,KAAO44B,EAAE54B,KAAKJ,cAGhBg5B,EAAEuF,YAAcvE,GAAWx4B,KAAMw3B,EAAE54B,MAInC28B,EAAW/D,EAAE7G,IAGP6G,EAAEuF,aAGFvF,EAAEnzB,OACNk3B,EAAa/D,EAAE7G,MAASwH,GAAYn4B,KAAMu7B,GAAa,IAAM,KAAQ/D,EAAEnzB,WAEhEmzB,GAAEnzB,MAILmzB,EAAEzmB,SAAU,IAChBymB,EAAE7G,IAAM0H,GAAIr4B,KAAMu7B,GAGjBA,EAASv2B,QAASqzB,GAAK,OAASH,MAGhCqD,GAAapD,GAAYn4B,KAAMu7B,GAAa,IAAM,KAAQ,KAAOrD,OAK/DV,EAAEwF,aACD/gC,EAAOo+B,aAAckB,IACzBlC,EAAMiD,iBAAkB,oBAAqBrgC,EAAOo+B,aAAckB,IAE9Dt/B,EAAOq+B,KAAMiB,IACjBlC,EAAMiD,iBAAkB,gBAAiBrgC,EAAOq+B,KAAMiB,MAKnD/D,EAAEnzB,MAAQmzB,EAAEuF,YAAcvF,EAAEiD,eAAgB,GAASl4B,EAAQk4B,cACjEpB,EAAMiD,iBAAkB,eAAgB9E,EAAEiD,aAI3CpB,EAAMiD,iBACL,SACA9E,EAAE0B,UAAW,IAAO1B,EAAEkD,QAASlD,EAAE0B,UAAU,IAC1C1B,EAAEkD,QAASlD,EAAE0B,UAAU,KAA8B,MAArB1B,EAAE0B,UAAW,GAAc,KAAOJ,GAAW,WAAa,IAC1FtB,EAAEkD,QAAS,KAIb,KAAM/4B,IAAK61B,GAAEyF,QACZ5D,EAAMiD,iBAAkB36B,EAAG61B,EAAEyF,QAASt7B,GAIvC,IAAK61B,EAAE0F,aAAgB1F,EAAE0F,WAAWx8B,KAAMm7B,EAAiBxC,EAAO7B,MAAQ,GAAmB,IAAVrtB,GAElF,MAAOkvB,GAAMsD,OAIdR,GAAW,OAGX,KAAMx6B,KAAOw4B,QAAS,EAAGj2B,MAAO,EAAG81B,SAAU,GAC5CX,EAAO13B,GAAK61B,EAAG71B,GAOhB,IAHAg6B,EAAYxC,GAA+BN,GAAYrB,EAAGj1B,EAAS82B,GAK5D,CACNA,EAAMx6B,WAAa,EAGd68B,GACJI,EAAmBz4B,QAAS,YAAcg2B,EAAO7B,IAG7CA,EAAEhyB,OAASgyB,EAAE3kB,QAAU,IAC3B4oB,EAAet4B,WAAW,WACzBk2B,EAAMsD,MAAM,YACVnF,EAAE3kB,SAGN,KACC1I,EAAQ,EACRwxB,EAAUwB,KAAMlB,EAAgB56B,GAC/B,MAAQ0C,GAET,KAAa,EAARoG,GAIJ,KAAMpG,EAHN1C,GAAM,GAAI0C,QArBZ1C,GAAM,GAAI,eA8BX,SAASA,GAAM44B,EAAQmD,EAAkBC,EAAWJ,GACnD,GAAIK,GAAWnD,EAASj2B,EAAO41B,EAAUyD,EACxCX,EAAaQ,CAGC,KAAVjzB,IAKLA,EAAQ,EAGHsxB,GACJ3oB,aAAc2oB,GAKfE,EAAYjgC,EAGZ8/B,EAAwByB,GAAW,GAGnC5D,EAAMx6B,WAAao7B,EAAS,EAAI,EAAI,EAG/BoD,IACJvD,EAAW0D,GAAqBhG,EAAG6B,EAAOgE,IAItCpD,GAAU,KAAgB,IAATA,GAA2B,MAAXA,GAGhCzC,EAAEwF,aACNO,EAAWlE,EAAM+C,kBAAkB,iBAC9BmB,IACJthC,EAAOo+B,aAAckB,GAAagC,GAEnCA,EAAWlE,EAAM+C,kBAAkB,QAC9BmB,IACJthC,EAAOq+B,KAAMiB,GAAagC,IAKZ,MAAXtD,GACJqD,GAAY,EACZV,EAAa,aAGS,MAAX3C,GACXqD,GAAY,EACZV,EAAa,gBAIbU,EAAYG,GAAajG,EAAGsC,GAC5B8C,EAAaU,EAAUnzB,MACvBgwB,EAAUmD,EAAUj5B,KACpBH,EAAQo5B,EAAUp5B,MAClBo5B,GAAap5B,KAKdA,EAAQ04B,GACH3C,IAAW2C,KACfA,EAAa,QACC,EAAT3C,IACJA,EAAS,KAMZZ,EAAMY,OAASA,EACfZ,EAAMuD,YAAeQ,GAAoBR,GAAe,GAGnDU,EACJjzB,EAASjH,YAAay4B,GAAmB1B,EAASyC,EAAYvD,IAE9DhvB,EAASqzB,WAAY7B,GAAmBxC,EAAOuD,EAAY14B,IAI5Dm1B,EAAM2C,WAAYA,GAClBA,EAAatgC,EAERggC,GACJI,EAAmBz4B,QAASi6B,EAAY,cAAgB,aACrDjE,EAAO7B,EAAG8F,EAAYnD,EAAUj2B,IAIpC63B,EAAiB/xB,SAAU6xB,GAAmBxC,EAAOuD,IAEhDlB,IACJI,EAAmBz4B,QAAS,gBAAkBg2B,EAAO7B,MAE3Cv7B,EAAOm+B,QAChBn+B,EAAOyC,MAAM2E,QAAQ,cAKxB,MAAOg2B,IAGRsE,UAAW,SAAUhN,EAAKzvB,GACzB,MAAOjF,GAAO0E,IAAKgwB,EAAKj1B,EAAWwF,EAAU,WAG9C08B,QAAS,SAAUjN,EAAKtsB,EAAMnD,GAC7B,MAAOjF,GAAO0E,IAAKgwB,EAAKtsB,EAAMnD,EAAU,UAS1C,SAASs8B,IAAqBhG,EAAG6B,EAAOgE,GACvC,GAAIQ,GAAeC,EAAIC,EAAen/B,EACrC6sB,EAAW+L,EAAE/L,SACbyN,EAAY1B,EAAE0B,UACd2B,EAAiBrD,EAAEqD,cAGpB,KAAMj8B,IAAQi8B,GACRj8B,IAAQy+B,KACZhE,EAAOwB,EAAej8B,IAAUy+B,EAAWz+B,GAK7C,OAA0B,MAAnBs6B,EAAW,GACjBA,EAAU9vB,QACL00B,IAAOpiC,IACXoiC,EAAKtG,EAAEiF,UAAYpD,EAAM+C,kBAAkB,gBAK7C,IAAK0B,EACJ,IAAMl/B,IAAQ6sB,GACb,GAAKA,EAAU7sB,IAAU6sB,EAAU7sB,GAAOoB,KAAM89B,GAAO,CACtD5E,EAAU5mB,QAAS1T,EACnB,OAMH,GAAKs6B,EAAW,IAAOmE,GACtBU,EAAgB7E,EAAW,OACrB,CAEN,IAAMt6B,IAAQy+B,GAAY,CACzB,IAAMnE,EAAW,IAAO1B,EAAEsD,WAAYl8B,EAAO,IAAMs6B,EAAU,IAAO,CACnE6E,EAAgBn/B,CAChB,OAEKi/B,IACLA,EAAgBj/B,GAIlBm/B,EAAgBA,GAAiBF,EAMlC,MAAKE,IACCA,IAAkB7E,EAAW,IACjCA,EAAU5mB,QAASyrB,GAEbV,EAAWU,IAJnB,EASD,QAASN,IAAajG,EAAGsC,GACxB,GAAIkE,GAAOC,EAASC,EAAM94B,EACzB01B,KACAn5B,EAAI,EAEJu3B,EAAY1B,EAAE0B,UAAUt8B,QACxB8uB,EAAOwN,EAAW,EAQnB,IALK1B,EAAE2G,aACNrE,EAAWtC,EAAE2G,WAAYrE,EAAUtC,EAAE5G,WAIjCsI,EAAW,GACf,IAAMgF,IAAQ1G,GAAEsD,WACfA,EAAYoD,EAAKh4B,eAAkBsxB,EAAEsD,WAAYoD,EAKnD,MAASD,EAAU/E,IAAYv3B,IAG9B,GAAiB,MAAZs8B,EAAkB,CAGtB,GAAc,MAATvS,GAAgBA,IAASuS,EAAU,CAMvC,GAHAC,EAAOpD,EAAYpP,EAAO,IAAMuS,IAAanD,EAAY,KAAOmD,IAG1DC,EACL,IAAMF,IAASlD,GAId,GADA11B,EAAM44B,EAAM91B,MAAM,KACb9C,EAAK,KAAQ64B,IAGjBC,EAAOpD,EAAYpP,EAAO,IAAMtmB,EAAK,KACpC01B,EAAY,KAAO11B,EAAK,KACb,CAEN84B,KAAS,EACbA,EAAOpD,EAAYkD,GAGRlD,EAAYkD,MAAY,IACnCC,EAAU74B,EAAK,GACf8zB,EAAUj3B,OAAQN,IAAK,EAAGs8B,GAG3B,OAOJ,GAAKC,KAAS,EAGb,GAAKA,GAAQ1G,EAAE,UACdsC,EAAWoE,EAAMpE,OAEjB,KACCA,EAAWoE,EAAMpE,GAChB,MAAQ/1B,GACT,OAASoG,MAAO,cAAejG,MAAOg6B,EAAOn6B,EAAI,sBAAwB2nB,EAAO,OAASuS,IAO7FvS,EAAOuS,EAIT,OAAS9zB,MAAO,UAAW9F,KAAMy1B,GAGlC79B,EAAOk/B,WACNT,SACC0D,OAAQ,6FAET3S,UACC2S,OAAQ,uBAETtD,YACCuD,cAAe,SAAUh4B,GAExB,MADApK,GAAO4J,WAAYQ,GACZA,MAMVpK,EAAOo/B,cAAe,SAAU,SAAU7D,GACpCA,EAAEzmB,QAAUrV,IAChB87B,EAAEzmB,OAAQ,GAENymB,EAAEsF,cACNtF,EAAE54B,KAAO,MACT44B,EAAEjgB,QAAS,KAKbtb,EAAOq/B,cAAe,SAAU,SAAS9D,GAGxC,GAAKA,EAAEsF,YAAc,CAEpB,GAAIsB,GACHE,EAAOxiC,EAASwiC,MAAQriC,EAAO,QAAQ,IAAMH,EAAS4J,eAEvD,QAECy3B,KAAM,SAAU70B,EAAGpH,GAElBk9B,EAAStiC,EAAS2I,cAAc,UAEhC25B,EAAO54B,OAAQ,EAEVgyB,EAAE+G,gBACNH,EAAOI,QAAUhH,EAAE+G,eAGpBH,EAAOj8B,IAAMq1B,EAAE7G,IAGfyN,EAAOK,OAASL,EAAOM,mBAAqB,SAAUp2B,EAAGq2B,IAEnDA,IAAYP,EAAOv/B,YAAc,kBAAkBmB,KAAMo+B,EAAOv/B,eAGpEu/B,EAAOK,OAASL,EAAOM,mBAAqB,KAGvCN,EAAO/9B,YACX+9B,EAAO/9B,WAAWgQ,YAAa+tB,GAIhCA,EAAS,KAGHO,GACLz9B,EAAU,IAAK,aAOlBo9B,EAAKpb,aAAckb,EAAQE,EAAKvxB,aAGjC4vB,MAAO,WACDyB,GACJA,EAAOK,OAAQ/iC,GAAW,OAM/B,IAAIkjC,OACHC,GAAS,mBAGV5iC,GAAOk/B,WACN2D,MAAO,WACPC,cAAe,WACd,GAAI79B,GAAW09B,GAAa5tB,OAAW/U,EAAOkT,QAAU,IAAQ+oB,IAEhE,OADA34B,MAAM2B,IAAa,EACZA,KAKTjF,EAAOo/B,cAAe,aAAc,SAAU7D,EAAGwH,EAAkB3F,GAElE,GAAI4F,GAAcC,EAAaC,EAC9BC,EAAW5H,EAAEsH,SAAU,IAAWD,GAAO7+B,KAAMw3B,EAAE7G,KAChD,MACkB,gBAAX6G,GAAEnzB,QAAwBmzB,EAAEiD,aAAe,IAAK39B,QAAQ,sCAAwC+hC,GAAO7+B,KAAMw3B,EAAEnzB,OAAU,OAIlI,OAAK+6B,IAAiC,UAArB5H,EAAE0B,UAAW,IAG7B+F,EAAezH,EAAEuH,cAAgB9iC,EAAOiE,WAAYs3B,EAAEuH,eACrDvH,EAAEuH,gBACFvH,EAAEuH,cAGEK,EACJ5H,EAAG4H,GAAa5H,EAAG4H,GAAWp6B,QAAS65B,GAAQ,KAAOI,GAC3CzH,EAAEsH,SAAU,IACvBtH,EAAE7G,MAASwH,GAAYn4B,KAAMw3B,EAAE7G,KAAQ,IAAM,KAAQ6G,EAAEsH,MAAQ,IAAMG,GAItEzH,EAAEsD,WAAW,eAAiB,WAI7B,MAHMqE,IACLljC,EAAOiI,MAAO+6B,EAAe,mBAEvBE,EAAmB,IAI3B3H,EAAE0B,UAAW,GAAM,OAGnBgG,EAAczjC,EAAQwjC,GACtBxjC,EAAQwjC,GAAiB,WACxBE,EAAoB59B,WAIrB83B,EAAMjvB,OAAO,WAEZ3O,EAAQwjC,GAAiBC,EAGpB1H,EAAGyH,KAEPzH,EAAEuH,cAAgBC,EAAiBD,cAGnCH,GAAaliC,KAAMuiC,IAIfE,GAAqBljC,EAAOiE,WAAYg/B,IAC5CA,EAAaC,EAAmB,IAGjCA,EAAoBD,EAAcxjC,IAI5B,UAtDR,GAyDD,IAAI2jC,IAAcC,GACjBC,GAAQ,EAERC,GAAmB/jC,EAAO8J,eAAiB,WAE1C,GAAIvB,EACJ,KAAMA,IAAOq7B,IACZA,GAAcr7B,GAAOtI,GAAW,GAKnC,SAAS+jC,MACR,IACC,MAAO,IAAIhkC,GAAOikC,eACjB,MAAO37B,KAGV,QAAS47B,MACR,IACC,MAAO,IAAIlkC,GAAO8J,cAAc,qBAC/B,MAAOxB,KAKV9H,EAAOy7B,aAAakI,IAAMnkC,EAAO8J,cAOhC,WACC,OAAQhG,KAAKg7B,SAAWkF,MAAuBE,MAGhDF,GAGDH,GAAerjC,EAAOy7B,aAAakI,MACnC3jC,EAAO6P,QAAQ+zB,OAASP,IAAkB,mBAAqBA,IAC/DA,GAAerjC,EAAO6P,QAAQ4kB,OAAS4O,GAGlCA,IAEJrjC,EAAOq/B,cAAc,SAAU9D,GAE9B,IAAMA,EAAEsF,aAAe7gC,EAAO6P,QAAQ+zB,KAAO,CAE5C,GAAI3+B,EAEJ,QACCi8B,KAAM,SAAUF,EAASjD,GAGxB,GAAI5hB,GAAQzW,EACXi+B,EAAMpI,EAAEoI,KAWT,IAPKpI,EAAEsI,SACNF,EAAIG,KAAMvI,EAAE54B,KAAM44B,EAAE7G,IAAK6G,EAAEhyB,MAAOgyB,EAAEsI,SAAUtI,EAAEzP,UAEhD6X,EAAIG,KAAMvI,EAAE54B,KAAM44B,EAAE7G,IAAK6G,EAAEhyB,OAIvBgyB,EAAEwI,UACN,IAAMr+B,IAAK61B,GAAEwI,UACZJ,EAAKj+B,GAAM61B,EAAEwI,UAAWr+B,EAKrB61B,GAAEiF,UAAYmD,EAAIpD,kBACtBoD,EAAIpD,iBAAkBhF,EAAEiF,UAQnBjF,EAAEsF,aAAgBG,EAAQ,sBAC/BA,EAAQ,oBAAsB,iBAI/B,KACC,IAAMt7B,IAAKs7B,GACV2C,EAAItD,iBAAkB36B,EAAGs7B,EAASt7B,IAElC,MAAOs+B,IAKTL,EAAIzC,KAAQ3F,EAAEuF,YAAcvF,EAAEnzB,MAAU,MAGxCnD,EAAW,SAAUoH,EAAGq2B,GACvB,GAAI1E,GAAQ2B,EAAiBgB,EAAYS,CAKzC,KAGC,GAAKn8B,IAAcy9B,GAA8B,IAAnBiB,EAAI/gC,YAcjC,GAXAqC,EAAWxF,EAGN0c,IACJwnB,EAAIlB,mBAAqBziC,EAAO2J,KAC3B45B,UACGH,IAAcjnB,IAKlBumB,EAEoB,IAAnBiB,EAAI/gC,YACR+gC,EAAIjD,YAEC,CACNU,KACApD,EAAS2F,EAAI3F,OACb2B,EAAkBgE,EAAIvD,wBAIW,gBAArBuD,GAAI7F,eACfsD,EAAUh3B,KAAOu5B,EAAI7F,aAKtB,KACC6C,EAAagD,EAAIhD,WAChB,MAAO74B,GAER64B,EAAa,GAQR3C,IAAUzC,EAAE+C,SAAY/C,EAAEsF,YAGT,OAAX7C,IACXA,EAAS,KAHTA,EAASoD,EAAUh3B,KAAO,IAAM,KAOlC,MAAO65B,GACFvB,GACL3E,EAAU,GAAIkG,GAKX7C,GACJrD,EAAUC,EAAQ2C,EAAYS,EAAWzB,IAIrCpE,EAAEhyB,MAGuB,IAAnBo6B,EAAI/gC,WAGfsE,WAAYjC,IAEZkX,IAAWmnB,GACNC,KAGEH,KACLA,MACApjC,EAAQR,GAAS0kC,OAAQX,KAG1BH,GAAcjnB,GAAWlX,GAE1B0+B,EAAIlB,mBAAqBx9B,GAjBzBA,KAqBFy7B,MAAO,WACDz7B,GACJA,EAAUxF,GAAW,OAO3B,IAAI0kC,IAAOC,GACVC,GAAW,yBACXC,GAAatnB,OAAQ,iBAAmBxb,EAAY,cAAe,KACnE+iC,GAAO,cACPC,IAAwBC,IACxBC,IACChG,KAAM,SAAU9mB,EAAM1N,GACrB,GAAIpE,GAAK6+B,EACRC,EAAQthC,KAAKuhC,YAAajtB,EAAM1N,GAChC4wB,EAAQwJ,GAAO7gC,KAAMyG,GACrB1D,EAASo+B,EAAMxuB,MACf7I,GAAS/G,GAAU,EACnBs+B,EAAQ,EACRC,EAAgB,EAEjB,IAAKjK,EAAQ,CAKZ,GAJAh1B,GAAOg1B,EAAM,GACb6J,EAAO7J,EAAM,KAAQ96B,EAAOu4B,UAAW3gB,GAAS,GAAK,MAGvC,OAAT+sB,GAAiBp3B,EAAQ,CAI7BA,EAAQvN,EAAO43B,IAAKgN,EAAMvhC,KAAMuU,GAAM,IAAU9R,GAAO,CAEvD,GAGCg/B,GAAQA,GAAS,KAGjBv3B,GAAgBu3B,EAChB9kC,EAAOyQ,MAAOm0B,EAAMvhC,KAAMuU,EAAMrK,EAAQo3B,SAI/BG,KAAWA,EAAQF,EAAMxuB,MAAQ5P,IAAqB,IAAVs+B,KAAiBC,GAGxEH,EAAMD,KAAOA,EACbC,EAAMr3B,MAAQA,EAEdq3B,EAAM9+B,IAAMg1B,EAAM,GAAKvtB,GAAUutB,EAAM,GAAK,GAAMh1B,EAAMA,EAEzD,MAAO8+B,KAKV,SAASI,MAIR,MAHA99B,YAAW,WACVi9B,GAAQ1kC,IAEA0kC,GAAQnkC,EAAOwL,MAGzB,QAASy5B,IAAcC,EAAWhmB,GACjClf,EAAOgF,KAAMka,EAAO,SAAUtH,EAAM1N,GACnC,GAAIi7B,IAAeT,GAAU9sB,QAAerX,OAAQmkC,GAAU,MAC7Dh3B,EAAQ,EACRlK,EAAS2hC,EAAW3hC,MACrB,MAAgBA,EAARkK,EAAgBA,IACvB,GAAKy3B,EAAYz3B,GAAQjJ,KAAMygC,EAAWttB,EAAM1N,GAG/C,SAMJ,QAASk7B,IAAW/hC,EAAMgiC,EAAY/+B,GACrC,GAAIoX,GACH4nB,EACA53B,EAAQ,EACRlK,EAASghC,GAAoBhhC,OAC7B4K,EAAWpO,EAAO2L,WAAWwC,OAAQ,iBAE7Bo3B,GAAKliC,OAEbkiC,EAAO,WACN,GAAKD,EACJ,OAAO,CAER,IAAIE,GAAcrB,IAASa,KAC1B31B,EAAY5E,KAAKC,IAAK,EAAGw6B,EAAUO,UAAYP,EAAUQ,SAAWF,GAEpEnY,EAAOhe,EAAY61B,EAAUQ,UAAY,EACzCC,EAAU,EAAItY,EACd3f,EAAQ,EACRlK,EAAS0hC,EAAUU,OAAOpiC,MAE3B,MAAgBA,EAARkK,EAAiBA,IACxBw3B,EAAUU,OAAQl4B,GAAQm4B,IAAKF,EAKhC,OAFAv3B,GAASsB,WAAYrM,GAAQ6hC,EAAWS,EAASt2B,IAElC,EAAVs2B,GAAeniC,EACZ6L,GAEPjB,EAASjH,YAAa9D,GAAQ6hC,KACvB,IAGTA,EAAY92B,EAASjJ,SACpB9B,KAAMA,EACN6b,MAAOlf,EAAOiG,UAAYo/B,GAC1BS,KAAM9lC,EAAOiG,QAAQ,GAAQ8/B,kBAAqBz/B,GAClD0/B,mBAAoBX,EACpBlI,gBAAiB72B,EACjBm/B,UAAWtB,IAASa,KACpBU,SAAUp/B,EAAQo/B,SAClBE,UACAf,YAAa,SAAUjtB,EAAM9R,GAC5B,GAAI8+B,GAAQ5kC,EAAOimC,MAAO5iC,EAAM6hC,EAAUY,KAAMluB,EAAM9R,EACpDo/B,EAAUY,KAAKC,cAAenuB,IAAUstB,EAAUY,KAAKI,OAEzD,OADAhB,GAAUU,OAAOnlC,KAAMmkC,GAChBA,GAERtuB,KAAM,SAAU6vB,GACf,GAAIz4B,GAAQ,EAGXlK,EAAS2iC,EAAUjB,EAAUU,OAAOpiC,OAAS,CAC9C,IAAK8hC,EACJ,MAAOhiC,KAGR,KADAgiC,GAAU,EACM9hC,EAARkK,EAAiBA,IACxBw3B,EAAUU,OAAQl4B,GAAQm4B,IAAK,EAUhC,OALKM,GACJ/3B,EAASjH,YAAa9D,GAAQ6hC,EAAWiB,IAEzC/3B,EAASqzB,WAAYp+B,GAAQ6hC,EAAWiB,IAElC7iC,QAGT4b,EAAQgmB,EAAUhmB,KAInB,KAFAknB,GAAYlnB,EAAOgmB,EAAUY,KAAKC,eAElBviC,EAARkK,EAAiBA,IAExB,GADAgQ,EAAS8mB,GAAqB92B,GAAQjJ,KAAMygC,EAAW7hC,EAAM6b,EAAOgmB,EAAUY,MAE7E,MAAOpoB,EAmBT,OAfAunB,IAAcC,EAAWhmB,GAEpBlf,EAAOiE,WAAYihC,EAAUY,KAAKv4B,QACtC23B,EAAUY,KAAKv4B,MAAM9I,KAAMpB,EAAM6hC,GAGlCllC,EAAO0W,GAAG2vB,MACTrmC,EAAOiG,OAAQs/B,GACdliC,KAAMA,EACNijC,KAAMpB,EACNpvB,MAAOovB,EAAUY,KAAKhwB,SAKjBovB,EAAUp2B,SAAUo2B,EAAUY,KAAKh3B,UACxC1J,KAAM8/B,EAAUY,KAAK1gC,KAAM8/B,EAAUY,KAAK/H,UAC1C1vB,KAAM62B,EAAUY,KAAKz3B,MACrBF,OAAQ+2B,EAAUY,KAAK33B,QAG1B,QAASi4B,IAAYlnB,EAAO6mB,GAC3B,GAAI77B,GAAO7D,EAAMqH,EAAOw4B,EAAQjwB,CAGhC,KAAMvI,IAASwR,GAed,GAdA7Y,EAAOrG,EAAO8J,UAAW4D,GACzBw4B,EAASH,EAAe1/B,GACxB6D,EAAQgV,EAAOxR,GACV1N,EAAO0G,QAASwD,KACpBg8B,EAASh8B,EAAO,GAChBA,EAAQgV,EAAOxR,GAAUxD,EAAO,IAG5BwD,IAAUrH,IACd6Y,EAAO7Y,GAAS6D,QACTgV,GAAOxR,IAGfuI,EAAQjW,EAAOq4B,SAAUhyB,GACpB4P,GAAS,UAAYA,GAAQ,CACjC/L,EAAQ+L,EAAM2kB,OAAQ1wB,SACfgV,GAAO7Y,EAId,KAAMqH,IAASxD,GACNwD,IAASwR,KAChBA,EAAOxR,GAAUxD,EAAOwD,GACxBq4B,EAAer4B,GAAUw4B,OAI3BH,GAAe1/B,GAAS6/B,EAK3BlmC,EAAOolC,UAAYplC,EAAOiG,OAAQm/B,IAEjCmB,QAAS,SAAUrnB,EAAOja,GACpBjF,EAAOiE,WAAYib,IACvBja,EAAWia,EACXA,GAAU,MAEVA,EAAQA,EAAMjT,MAAM,IAGrB,IAAI2L,GACHlK,EAAQ,EACRlK,EAAS0b,EAAM1b,MAEhB,MAAgBA,EAARkK,EAAiBA,IACxBkK,EAAOsH,EAAOxR,GACdg3B,GAAU9sB,GAAS8sB,GAAU9sB,OAC7B8sB,GAAU9sB,GAAOvB,QAASpR,IAI5BuhC,UAAW,SAAUvhC,EAAUyuB,GACzBA,EACJ8Q,GAAoBnuB,QAASpR,GAE7Bu/B,GAAoB/jC,KAAMwE,KAK7B,SAASw/B,IAAkBphC,EAAM6b,EAAO4mB,GAEvC,GAAIluB,GAAMlK,EAAOlK,EAChB0G,EAAOu8B,EAAUtO,EACjByM,EAAO3uB,EAAOywB,EACdJ,EAAOhjC,KACPmN,EAAQpN,EAAKoN,MACb8Q,KACAolB,KACA5O,EAAS10B,EAAKQ,UAAY6zB,GAAUr0B,EAG/ByiC,GAAKhwB,QACVG,EAAQjW,EAAOkW,YAAa7S,EAAM,MACX,MAAlB4S,EAAM2wB,WACV3wB,EAAM2wB,SAAW,EACjBF,EAAUzwB,EAAMtI,MAAMV,KACtBgJ,EAAMtI,MAAMV,KAAO,WACZgJ,EAAM2wB,UACXF,MAIHzwB,EAAM2wB,WAENN,EAAKn4B,OAAO,WAGXm4B,EAAKn4B,OAAO,WACX8H,EAAM2wB,WACA5mC,EAAO8V,MAAOzS,EAAM,MAAOG,QAChCyS,EAAMtI,MAAMV,YAOO,IAAlB5J,EAAKQ,WAAoB,UAAYqb,IAAS,SAAWA,MAK7D4mB,EAAKe,UAAap2B,EAAMo2B,SAAUp2B,EAAMq2B,UAAWr2B,EAAMs2B,WAIlB,WAAlC/mC,EAAO43B,IAAKv0B,EAAM,YACW,SAAhCrD,EAAO43B,IAAKv0B,EAAM,WAIbrD,EAAO6P,QAAQmC,wBAAkE,WAAxCgmB,GAAoB30B,EAAK2G,UAIvEyG,EAAM0D,KAAO,EAHb1D,EAAMiD,QAAU,iBAQdoyB,EAAKe,WACTp2B,EAAMo2B,SAAW,SACX7mC,EAAO6P,QAAQoC,kBACpBq0B,EAAKn4B,OAAO,WACXsC,EAAMo2B,SAAWf,EAAKe,SAAU,GAChCp2B,EAAMq2B,UAAYhB,EAAKe,SAAU,GACjCp2B,EAAMs2B,UAAYjB,EAAKe,SAAU,KAOpC,KAAMn5B,IAASwR,GAEd,GADAhV,EAAQgV,EAAOxR,GACV22B,GAAS5gC,KAAMyG,GAAU,CAG7B,SAFOgV,GAAOxR,GACdyqB,EAASA,GAAoB,WAAVjuB,EACdA,KAAY6tB,EAAS,OAAS,QAClC,QAED4O,GAAQlmC,KAAMiN,GAKhB,GADAlK,EAASmjC,EAAQnjC,OACH,CACbijC,EAAWzmC,EAAO0V,MAAOrS,EAAM,WAAcrD,EAAO0V,MAAOrS,EAAM,aAC5D,UAAYojC,KAChB1O,EAAS0O,EAAS1O,QAIdI,IACJsO,EAAS1O,QAAUA,GAEfA,EACJ/3B,EAAQqD,GAAOy0B,OAEfwO,EAAKlhC,KAAK,WACTpF,EAAQqD,GAAO60B,SAGjBoO,EAAKlhC,KAAK,WACT,GAAIwS,EACJ5X,GAAO2V,YAAatS,EAAM,SAC1B,KAAMuU,IAAQ2J,GACbvhB,EAAOyQ,MAAOpN,EAAMuU,EAAM2J,EAAM3J,KAGlC,KAAMlK,EAAQ,EAAYlK,EAARkK,EAAiBA,IAClCkK,EAAO+uB,EAASj5B,GAChBk3B,EAAQ0B,EAAKzB,YAAajtB,EAAMmgB,EAAS0O,EAAU7uB,GAAS,GAC5D2J,EAAM3J,GAAS6uB,EAAU7uB,IAAU5X,EAAOyQ,MAAOpN,EAAMuU,GAE/CA,IAAQ6uB,KACfA,EAAU7uB,GAASgtB,EAAMr3B,MACpBwqB,IACJ6M,EAAM9+B,IAAM8+B,EAAMr3B,MAClBq3B,EAAMr3B,MAAiB,UAATqK,GAA6B,WAATA,EAAoB,EAAI,KAO/D,QAASquB,IAAO5iC,EAAMiD,EAASsR,EAAM9R,EAAKogC,GACzC,MAAO,IAAID,IAAMhjC,UAAU1B,KAAM8B,EAAMiD,EAASsR,EAAM9R,EAAKogC,GAE5DlmC,EAAOimC,MAAQA,GAEfA,GAAMhjC,WACLE,YAAa8iC,GACb1kC,KAAM,SAAU8B,EAAMiD,EAASsR,EAAM9R,EAAKogC,EAAQvB,GACjDrhC,KAAKD,KAAOA,EACZC,KAAKsU,KAAOA,EACZtU,KAAK4iC,OAASA,GAAU,QACxB5iC,KAAKgD,QAAUA,EACfhD,KAAKiK,MAAQjK,KAAKkI,IAAMlI,KAAK8S,MAC7B9S,KAAKwC,IAAMA,EACXxC,KAAKqhC,KAAOA,IAAU3kC,EAAOu4B,UAAW3gB,GAAS,GAAK,OAEvDxB,IAAK,WACJ,GAAIH,GAAQgwB,GAAM9rB,UAAW7W,KAAKsU,KAElC,OAAO3B,IAASA,EAAMvR,IACrBuR,EAAMvR,IAAKpB,MACX2iC,GAAM9rB,UAAU8D,SAASvZ,IAAKpB,OAEhCuiC,IAAK,SAAUF,GACd,GAAIqB,GACH/wB,EAAQgwB,GAAM9rB,UAAW7W,KAAKsU,KAoB/B,OAjBCtU,MAAKwsB,IAAMkX,EADP1jC,KAAKgD,QAAQo/B,SACE1lC,EAAOkmC,OAAQ5iC,KAAK4iC,QACtCP,EAASriC,KAAKgD,QAAQo/B,SAAWC,EAAS,EAAG,EAAGriC,KAAKgD,QAAQo/B,UAG3CC,EAEpBriC,KAAKkI,KAAQlI,KAAKwC,IAAMxC,KAAKiK,OAAUy5B,EAAQ1jC,KAAKiK,MAE/CjK,KAAKgD,QAAQ2gC,MACjB3jC,KAAKgD,QAAQ2gC,KAAKxiC,KAAMnB,KAAKD,KAAMC,KAAKkI,IAAKlI,MAGzC2S,GAASA,EAAM0C,IACnB1C,EAAM0C,IAAKrV,MAEX2iC,GAAM9rB,UAAU8D,SAAStF,IAAKrV,MAExBA,OAIT2iC,GAAMhjC,UAAU1B,KAAK0B,UAAYgjC,GAAMhjC,UAEvCgjC,GAAM9rB,WACL8D,UACCvZ,IAAK,SAAUkgC,GACd,GAAIlnB,EAEJ,OAAiC,OAA5BknB,EAAMvhC,KAAMuhC,EAAMhtB,OACpBgtB,EAAMvhC,KAAKoN,OAA2C,MAAlCm0B,EAAMvhC,KAAKoN,MAAOm0B,EAAMhtB,OAQ/C8F,EAAS1d,EAAO43B,IAAKgN,EAAMvhC,KAAMuhC,EAAMhtB,KAAM,IAErC8F,GAAqB,SAAXA,EAAwBA,EAAJ,GAT9BknB,EAAMvhC,KAAMuhC,EAAMhtB,OAW3Be,IAAK,SAAUisB,GAGT5kC,EAAO0W,GAAGuwB,KAAMrC,EAAMhtB,MAC1B5X,EAAO0W,GAAGuwB,KAAMrC,EAAMhtB,MAAQgtB,GACnBA,EAAMvhC,KAAKoN,QAAgE,MAArDm0B,EAAMvhC,KAAKoN,MAAOzQ,EAAO84B,SAAU8L,EAAMhtB,QAAoB5X,EAAOq4B,SAAUuM,EAAMhtB,OACrH5X,EAAOyQ,MAAOm0B,EAAMvhC,KAAMuhC,EAAMhtB,KAAMgtB,EAAMp5B,IAAMo5B,EAAMD,MAExDC,EAAMvhC,KAAMuhC,EAAMhtB,MAASgtB,EAAMp5B,OASrCy6B,GAAM9rB,UAAUgG,UAAY8lB,GAAM9rB,UAAU4F,YAC3CpH,IAAK,SAAUisB,GACTA,EAAMvhC,KAAKQ,UAAY+gC,EAAMvhC,KAAKe,aACtCwgC,EAAMvhC,KAAMuhC,EAAMhtB,MAASgtB,EAAMp5B,OAKpCxL,EAAOgF,MAAO,SAAU,OAAQ,QAAU,SAAUU,EAAGW,GACtD,GAAI6gC,GAAQlnC,EAAOsB,GAAI+E,EACvBrG,GAAOsB,GAAI+E,GAAS,SAAU8gC,EAAOjB,EAAQjhC,GAC5C,MAAgB,OAATkiC,GAAkC,iBAAVA,GAC9BD,EAAM7hC,MAAO/B,KAAMgC,WACnBhC,KAAK8jC,QAASC,GAAOhhC,GAAM,GAAQ8gC,EAAOjB,EAAQjhC,MAIrDjF,EAAOsB,GAAG2E,QACTqhC,OAAQ,SAAUH,EAAOI,EAAIrB,EAAQjhC,GAGpC,MAAO3B,MAAK+b,OAAQqY,IAAWE,IAAK,UAAW,GAAIE,OAGjDhyB,MAAMshC,SAAUj2B,QAASo2B,GAAMJ,EAAOjB,EAAQjhC,IAEjDmiC,QAAS,SAAUxvB,EAAMuvB,EAAOjB,EAAQjhC,GACvC,GAAI0I,GAAQ3N,EAAOgI,cAAe4P,GACjC4vB,EAASxnC,EAAOmnC,MAAOA,EAAOjB,EAAQjhC,GACtCwiC,EAAc,WAEb,GAAInB,GAAOlB,GAAW9hC,KAAMtD,EAAOiG,UAAY2R,GAAQ4vB,EACvDC,GAAYC,OAAS,WACpBpB,EAAKhwB,MAAM,KAGP3I,GAAS3N,EAAO0V,MAAOpS,KAAM,YACjCgjC,EAAKhwB,MAAM,GAKd,OAFCmxB,GAAYC,OAASD,EAEf95B,GAAS65B,EAAO1xB,SAAU,EAChCxS,KAAK0B,KAAMyiC,GACXnkC,KAAKwS,MAAO0xB,EAAO1xB,MAAO2xB,IAE5BnxB,KAAM,SAAU3T,EAAMmU,EAAYqvB,GACjC,GAAIwB,GAAY,SAAU1xB,GACzB,GAAIK,GAAOL,EAAMK,WACVL,GAAMK,KACbA,EAAM6vB,GAYP,OATqB,gBAATxjC,KACXwjC,EAAUrvB,EACVA,EAAanU,EACbA,EAAOlD,GAEHqX,GAAcnU,KAAS,GAC3BW,KAAKwS,MAAOnT,GAAQ,SAGdW,KAAK0B,KAAK,WAChB,GAAI+Q,IAAU,EACbrI,EAAgB,MAAR/K,GAAgBA,EAAO,aAC/BilC,EAAS5nC,EAAO4nC,OAChBx/B,EAAOpI,EAAO0V,MAAOpS,KAEtB,IAAKoK,EACCtF,EAAMsF,IAAWtF,EAAMsF,GAAQ4I,MACnCqxB,EAAWv/B,EAAMsF,QAGlB,KAAMA,IAAStF,GACTA,EAAMsF,IAAWtF,EAAMsF,GAAQ4I,MAAQiuB,GAAKxgC,KAAM2J,IACtDi6B,EAAWv/B,EAAMsF,GAKpB,KAAMA,EAAQk6B,EAAOpkC,OAAQkK,KACvBk6B,EAAQl6B,GAAQrK,OAASC,MAAiB,MAARX,GAAgBilC,EAAQl6B,GAAQoI,QAAUnT,IAChFilC,EAAQl6B,GAAQ44B,KAAKhwB,KAAM6vB,GAC3BpwB,GAAU,EACV6xB,EAAO5hC,OAAQ0H,EAAO,KAOnBqI,IAAYowB,IAChBnmC,EAAO+V,QAASzS,KAAMX,MAIzB+kC,OAAQ,SAAU/kC,GAIjB,MAHKA,MAAS,IACbA,EAAOA,GAAQ,MAETW,KAAK0B,KAAK,WAChB,GAAI0I,GACHtF,EAAOpI,EAAO0V,MAAOpS,MACrBwS,EAAQ1N,EAAMzF,EAAO,SACrBsT,EAAQ7N,EAAMzF,EAAO,cACrBilC,EAAS5nC,EAAO4nC,OAChBpkC,EAASsS,EAAQA,EAAMtS,OAAS,CAajC,KAVA4E,EAAKs/B,QAAS,EAGd1nC,EAAO8V,MAAOxS,KAAMX,MAEfsT,GAASA,EAAMG,KAAOH,EAAMG,IAAIsxB,QACpCzxB,EAAMG,IAAIsxB,OAAOjjC,KAAMnB,MAIlBoK,EAAQk6B,EAAOpkC,OAAQkK,KACvBk6B,EAAQl6B,GAAQrK,OAASC,MAAQskC,EAAQl6B,GAAQoI,QAAUnT,IAC/DilC,EAAQl6B,GAAQ44B,KAAKhwB,MAAM,GAC3BsxB,EAAO5hC,OAAQ0H,EAAO,GAKxB,KAAMA,EAAQ,EAAWlK,EAARkK,EAAgBA,IAC3BoI,EAAOpI,IAAWoI,EAAOpI,GAAQg6B,QACrC5xB,EAAOpI,GAAQg6B,OAAOjjC,KAAMnB,YAKvB8E,GAAKs/B,WAMf,SAASL,IAAO1kC,EAAMklC,GACrB,GAAItoB,GACH3J,GAAUkyB,OAAQnlC,GAClB+C,EAAI,CAKL,KADAmiC,EAAeA,EAAc,EAAI,EACtB,EAAJniC,EAAQA,GAAK,EAAImiC,EACvBtoB,EAAQ8X,GAAW3xB,GACnBkQ,EAAO,SAAW2J,GAAU3J,EAAO,UAAY2J,GAAU5c,CAO1D,OAJKklC,KACJjyB,EAAMzE,QAAUyE,EAAM3B,MAAQtR,GAGxBiT,EAIR5V,EAAOgF,MACN+iC,UAAWV,GAAM,QACjBW,QAASX,GAAM,QACfY,YAAaZ,GAAM,UACnBa,QAAU/2B,QAAS,QACnBg3B,SAAWh3B,QAAS,QACpBi3B,YAAcj3B,QAAS,WACrB,SAAU9K,EAAM6Y,GAClBlf,EAAOsB,GAAI+E,GAAS,SAAU8gC,EAAOjB,EAAQjhC,GAC5C,MAAO3B,MAAK8jC,QAASloB,EAAOioB,EAAOjB,EAAQjhC,MAI7CjF,EAAOmnC,MAAQ,SAAUA,EAAOjB,EAAQ5kC,GACvC,GAAI4O,GAAMi3B,GAA0B,gBAAVA,GAAqBnnC,EAAOiG,UAAYkhC,IACjEpJ,SAAUz8B,IAAOA,GAAM4kC,GACtBlmC,EAAOiE,WAAYkjC,IAAWA,EAC/BzB,SAAUyB,EACVjB,OAAQ5kC,GAAM4kC,GAAUA,IAAWlmC,EAAOiE,WAAYiiC,IAAYA,EAwBnE,OArBAh2B,GAAIw1B,SAAW1lC,EAAO0W,GAAGrP,IAAM,EAA4B,gBAAjB6I,GAAIw1B,SAAwBx1B,EAAIw1B,SACzEx1B,EAAIw1B,WAAY1lC,GAAO0W,GAAGC,OAAS3W,EAAO0W,GAAGC,OAAQzG,EAAIw1B,UAAa1lC,EAAO0W,GAAGC,OAAOsH,UAGtE,MAAb/N,EAAI4F,OAAiB5F,EAAI4F,SAAU,KACvC5F,EAAI4F,MAAQ,MAIb5F,EAAIiW,IAAMjW,EAAI6tB,SAEd7tB,EAAI6tB,SAAW,WACT/9B,EAAOiE,WAAYiM,EAAIiW,MAC3BjW,EAAIiW,IAAI1hB,KAAMnB,MAGV4M,EAAI4F,OACR9V,EAAO+V,QAASzS,KAAM4M,EAAI4F,QAIrB5F,GAGRlQ,EAAOkmC,QACNmC,OAAQ,SAAUC,GACjB,MAAOA,IAERC,MAAO,SAAUD,GAChB,MAAO,GAAM79B,KAAK+9B,IAAKF,EAAE79B,KAAKg+B,IAAO,IAIvCzoC,EAAO4nC,UACP5nC,EAAO0W,GAAKuvB,GAAMhjC,UAAU1B,KAC5BvB,EAAO0W,GAAG6uB,KAAO,WAChB,GAAIc,GACHuB,EAAS5nC,EAAO4nC,OAChBliC,EAAI,CAIL,KAFAy+B,GAAQnkC,EAAOwL,MAEHo8B,EAAOpkC,OAAXkC,EAAmBA,IAC1B2gC,EAAQuB,EAAQliC,GAEV2gC,KAAWuB,EAAQliC,KAAQ2gC,GAChCuB,EAAO5hC,OAAQN,IAAK,EAIhBkiC,GAAOpkC,QACZxD,EAAO0W,GAAGJ,OAEX6tB,GAAQ1kC,GAGTO,EAAO0W,GAAG2vB,MAAQ,SAAUA,GACtBA,KAAWrmC,EAAO4nC,OAAOnnC,KAAM4lC,IACnCrmC,EAAO0W,GAAGnJ,SAIZvN,EAAO0W,GAAGgyB,SAAW,GAErB1oC,EAAO0W,GAAGnJ,MAAQ,WACX62B,KACLA,GAAUuE,YAAa3oC,EAAO0W,GAAG6uB,KAAMvlC,EAAO0W,GAAGgyB,YAInD1oC,EAAO0W,GAAGJ,KAAO,WAChBsyB,cAAexE,IACfA,GAAU,MAGXpkC,EAAO0W,GAAGC,QACTkyB,KAAM,IACNC,KAAM,IAEN7qB,SAAU,KAIXje,EAAO0W,GAAGuwB,QAELjnC,EAAOyc,MAAQzc,EAAOyc,KAAKwS,UAC/BjvB,EAAOyc,KAAKwS,QAAQ8Z,SAAW,SAAU1lC,GACxC,MAAOrD,GAAO6K,KAAK7K,EAAO4nC,OAAQ,SAAUtmC,GAC3C,MAAO+B,KAAS/B,EAAG+B,OACjBG,SAGLxD,EAAOsB,GAAG0nC,OAAS,SAAU1iC,GAC5B,GAAKhB,UAAU9B,OACd,MAAO8C,KAAY7G,EAClB6D,KACAA,KAAK0B,KAAK,SAAUU,GACnB1F,EAAOgpC,OAAOC,UAAW3lC,KAAMgD,EAASZ,IAI3C,IAAIud,GAASimB,EACZC,GAAQt9B,IAAK,EAAG0tB,KAAM,GACtBl2B,EAAOC,KAAM,GACbqc,EAAMtc,GAAQA,EAAKS,aAEpB,IAAM6b,EAON,MAHAsD,GAAUtD,EAAIlW,gBAGRzJ,EAAOyhB,SAAUwB,EAAS5f,UAMpBA,GAAK+lC,wBAA0BxpC,IAC1CupC,EAAM9lC,EAAK+lC,yBAEZF,EAAMG,GAAW1pB,IAEhB9T,IAAKs9B,EAAIt9B,KAASq9B,EAAII,aAAermB,EAAQ9C,YAAiB8C,EAAQ7C,WAAc,GACpFmZ,KAAM4P,EAAI5P,MAAS2P,EAAIK,aAAetmB,EAAQlD,aAAiBkD,EAAQjD,YAAc,KAX9EmpB,GAeTnpC,EAAOgpC,QAENC,UAAW,SAAU5lC,EAAMiD,EAASZ,GACnC,GAAIsxB,GAAWh3B,EAAO43B,IAAKv0B,EAAM,WAGf,YAAb2zB,IACJ3zB,EAAKoN,MAAMumB,SAAW,WAGvB,IAAIwS,GAAUxpC,EAAQqD,GACrBomC,EAAYD,EAAQR,SACpBU,EAAY1pC,EAAO43B,IAAKv0B,EAAM,OAC9BsmC,EAAa3pC,EAAO43B,IAAKv0B,EAAM,QAC/BumC,GAAmC,aAAb5S,GAAwC,UAAbA,IAA0Bh3B,EAAOwK,QAAQ,QAASk/B,EAAWC,IAAe,GAC7HzqB,KAAY2qB,KAAkBC,EAAQC,CAGlCH,IACJC,EAAcL,EAAQxS,WACtB8S,EAASD,EAAYh+B,IACrBk+B,EAAUF,EAAYtQ,OAEtBuQ,EAASniC,WAAY+hC,IAAe,EACpCK,EAAUpiC,WAAYgiC,IAAgB,GAGlC3pC,EAAOiE,WAAYqC,KACvBA,EAAUA,EAAQ7B,KAAMpB,EAAMqC,EAAG+jC,IAGd,MAAfnjC,EAAQuF,MACZqT,EAAMrT,IAAQvF,EAAQuF,IAAM49B,EAAU59B,IAAQi+B,GAE1B,MAAhBxjC,EAAQizB,OACZra,EAAMqa,KAASjzB,EAAQizB,KAAOkQ,EAAUlQ,KAASwQ,GAG7C,SAAWzjC,GACfA,EAAQ0jC,MAAMvlC,KAAMpB,EAAM6b,GAE1BsqB,EAAQ5R,IAAK1Y,KAMhBlf,EAAOsB,GAAG2E,QAET+wB,SAAU,WACT,GAAM1zB,KAAM,GAAZ,CAIA,GAAI2mC,GAAcjB,EACjBkB,GAAiBr+B,IAAK,EAAG0tB,KAAM,GAC/Bl2B,EAAOC,KAAM,EAwBd,OArBwC,UAAnCtD,EAAO43B,IAAKv0B,EAAM,YAEtB2lC,EAAS3lC,EAAK+lC,yBAGda,EAAe3mC,KAAK2mC,eAGpBjB,EAAS1lC,KAAK0lC,SACRhpC,EAAOgK,SAAUigC,EAAc,GAAK,UACzCC,EAAeD,EAAajB,UAI7BkB,EAAar+B,KAAQ7L,EAAO43B,IAAKqS,EAAc,GAAK,kBAAkB,GACtEC,EAAa3Q,MAAQv5B,EAAO43B,IAAKqS,EAAc,GAAK,mBAAmB,KAOvEp+B,IAAMm9B,EAAOn9B,IAAOq+B,EAAar+B,IAAM7L,EAAO43B,IAAKv0B,EAAM,aAAa,GACtEk2B,KAAMyP,EAAOzP,KAAO2Q,EAAa3Q,KAAOv5B,EAAO43B,IAAKv0B,EAAM,cAAc,MAI1E4mC,aAAc,WACb,MAAO3mC,MAAKuC,IAAI,WACf,GAAIokC,GAAe3mC,KAAK2mC,cAAgBpqC,EAAS4J,eACjD,OAAQwgC,IAAmBjqC,EAAOgK,SAAUigC,EAAc,SAAsD,WAA1CjqC,EAAO43B,IAAKqS,EAAc,YAC/FA,EAAeA,EAAaA,YAE7B,OAAOA,IAAgBpqC,EAAS4J,qBAOnCzJ,EAAOgF,MAAO+a,WAAY,cAAeI,UAAW,eAAgB,SAAU8d,EAAQrmB,GACrF,GAAI/L,GAAM,IAAI9H,KAAM6T,EAEpB5X,GAAOsB,GAAI28B,GAAW,SAAUxlB,GAC/B,MAAOzY,GAAOmL,OAAQ7H,KAAM,SAAUD,EAAM46B,EAAQxlB,GACnD,GAAIywB,GAAMG,GAAWhmC,EAErB,OAAKoV,KAAQhZ,EACLypC,EAAOtxB,IAAQsxB,GAAOA,EAAKtxB,GACjCsxB,EAAIrpC,SAAS4J,gBAAiBw0B,GAC9B56B,EAAM46B,IAGHiL,EACJA,EAAIiB,SACFt+B,EAAY7L,EAAQkpC,GAAMnpB,aAApBtH,EACP5M,EAAM4M,EAAMzY,EAAQkpC,GAAM/oB,aAI3B9c,EAAM46B,GAAWxlB,EAPlB,IASEwlB,EAAQxlB,EAAKnT,UAAU9B,OAAQ,QAIpC,SAAS6lC,IAAWhmC,GACnB,MAAOrD,GAAOwH,SAAUnE,GACvBA,EACkB,IAAlBA,EAAKQ,SACJR,EAAKua,aAAeva,EAAKwa,cACzB,EAGH7d,EAAOgF,MAAQolC,OAAQ,SAAUC,MAAO,SAAW,SAAUhkC,EAAM1D,GAClE3C,EAAOgF,MAAQw1B,QAAS,QAAUn0B,EAAMikC,QAAS3nC,EAAM,GAAI,QAAU0D,GAAQ,SAAUkkC,EAAcC,GAEpGxqC,EAAOsB,GAAIkpC,GAAa,SAAUjQ,EAAQrwB,GACzC,GAAIkB,GAAY9F,UAAU9B,SAAY+mC,GAAkC,iBAAXhQ,IAC5DvB,EAAQuR,IAAkBhQ,KAAW,GAAQrwB,KAAU,EAAO,SAAW,SAE1E,OAAOlK,GAAOmL,OAAQ7H,KAAM,SAAUD,EAAMV,EAAMuH,GACjD,GAAIyV,EAEJ,OAAK3f,GAAOwH,SAAUnE,GAIdA,EAAKxD,SAAS4J,gBAAiB,SAAWpD,GAI3B,IAAlBhD,EAAKQ,UACT8b,EAAMtc,EAAKoG,gBAIJgB,KAAKC,IACXrH,EAAK4D,KAAM,SAAWZ,GAAQsZ,EAAK,SAAWtZ,GAC9ChD,EAAK4D,KAAM,SAAWZ,GAAQsZ,EAAK,SAAWtZ,GAC9CsZ,EAAK,SAAWtZ,KAIX6D,IAAUzK,EAEhBO,EAAO43B,IAAKv0B,EAAMV,EAAMq2B,GAGxBh5B,EAAOyQ,MAAOpN,EAAMV,EAAMuH,EAAO8uB,IAChCr2B,EAAMyI,EAAYmvB,EAAS96B,EAAW2L,EAAW,WASvD5L,EAAOQ,OAASR,EAAOU,EAAIF,EAcJ,kBAAXyqC,SAAyBA,OAAOC,KAAOD,OAAOC,IAAI1qC,QAC7DyqC,OAAQ,YAAc,WAAc,MAAOzqC,OAGxCR"} \ No newline at end of file
diff --git a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/js/bootstrap.js b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/js/bootstrap.js
deleted file mode 100644
index 72b73e4b..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/js/bootstrap.js
+++ /dev/null
@@ -1,1951 +0,0 @@
-/*!
- * 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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/js/bootstrap.min.js b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/js/bootstrap.min.js
deleted file mode 100755
index 4fae3fa3..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/js/bootstrap.min.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/*!
- * 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/_exts/taler_sphinx_theme/guzzle_sphinx_theme/theme.conf b/_exts/taler_sphinx_theme/guzzle_sphinx_theme/theme.conf
deleted file mode 100644
index 03638c42..00000000
--- a/_exts/taler_sphinx_theme/guzzle_sphinx_theme/theme.conf
+++ /dev/null
@@ -1,40 +0,0 @@
-[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/_static/custom.css b/_static/custom.css
new file mode 100644
index 00000000..d34fd74e
--- /dev/null
+++ b/_static/custom.css
@@ -0,0 +1,15 @@
+@media (min-width: 960px) {
+ .container {
+ max-width: 100rem;
+ }
+
+ .bd-sidebar {
+ flex-basis: 25%;
+ }
+}
+
+@media (min-width: 768px) {
+ .bd-sidebar {
+ max-width: 25%;
+ }
+}
diff --git a/_static/sample-pos-config.json b/_static/sample-pos-config.json
index f0789104..db4dca6e 100644
--- a/_static/sample-pos-config.json
+++ b/_static/sample-pos-config.json
@@ -1,7 +1,7 @@
{
"config": {
"base_url": "https://backend.demo.taler.net/instances/pos",
- "api_key": "sandbox"
+ "api_key": "secret-token:sandbox"
},
"categories": [
{
diff --git a/arch-api.png b/arch-api.png
deleted file mode 100644
index 8004f790..00000000
--- a/arch-api.png
+++ /dev/null
Binary files differ
diff --git a/arch.png b/arch.png
deleted file mode 100644
index 37fc845b..00000000
--- a/arch.png
+++ /dev/null
Binary files differ
diff --git a/backoffice-product-create.stock.svg b/backoffice-product-create.stock.svg
deleted file mode 100644
index 3a60b19f..00000000
--- a/backoffice-product-create.stock.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2664.430097077814 3110.5102161527097" width="2664.430097077814" height="3110.5102161527097">
- <!-- svg-source:excalidraw -->
-
- <defs>
- <style>
- @font-face {
- font-family: "Virgil";
- src: url("https://excalidraw.com/Virgil.woff2");
- }
- @font-face {
- font-family: "Cascadia";
- src: url("https://excalidraw.com/Cascadia.woff2");
- }
- </style>
- </defs>
- <rect x="0" y="0" width="2664.430097077814" height="3110.5102161527097" fill="#ffffff"></rect><g transform="translate(10 80.94624914970746) rotate(0 412 84.5)"><path d="M0 0 C236.0917525626719 0, 472.1835051253438 0, 824 0 M0 0 C176.35285029634835 0, 352.7057005926967 0, 824 0 M824 0 C824 49.4694261523895, 824 98.938852304779, 824 169 M824 0 C824 67.28842992009595, 824 134.5768598401919, 824 169 M824 169 C617.4895157001913 169, 410.9790314003825 169, 0 169 M824 169 C591.9370339371264 169, 359.8740678742528 169, 0 169 M0 169 C0 117.27438288601115, 0 65.5487657720223, 0 0 M0 169 C0 113.33390512643382, 0 57.66781025286764, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(103 150.94624914970746) rotate(0 25 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Stock</text></g><g transform="translate(195 136.19977029409756) rotate(0 91.5 26.5)"><path d="M0 0 C45.52723533092067 0, 91.05447066184134 0, 183 0 M0 0 C51.992949485499416 0, 103.98589897099883 0, 183 0 M183 0 C183 11.300868693832308, 183 22.601737387664617, 183 53 M183 0 C183 11.438832641299815, 183 22.87766528259963, 183 53 M183 53 C122.95858201207594 53, 62.91716402415186 53, 0 53 M183 53 C130.75365380672739 53, 78.50730761345476 53, 0 53 M0 53 C0 34.84640925144777, 0 16.692818502895534, 0 0 M0 53 C0 40.84659901196137, 0 28.69319802392274, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(223 151.19977029409756) rotate(0 62.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">manage stock</text></g><g transform="translate(907.7142857142858 69.91405600838334) rotate(0 412 208.375)"><path d="M0 0 C254.33701222166422 0, 508.67402444332845 0, 824 0 M0 0 C264.9951364375651 0, 529.9902728751302 0, 824 0 M824 0 C824 153.41329097186681, 824 306.82658194373363, 824 416.75 M824 0 C824 126.50023594351951, 824 253.00047188703903, 824 416.75 M824 416.75 C651.8076281763613 416.75, 479.6152563527226 416.75, 0 416.75 M824 416.75 C609.0305379532277 416.75, 394.06107590645547 416.75, 0 416.75 M0 416.75 C0 306.4687552821124, 0 196.1875105642248, 0 0 M0 416.75 C0 326.79617198703346, 0 236.8423439740669, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1000.7142857142858 139.91405600838334) rotate(0 25 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Stock</text></g><g transform="translate(999.7142857142858 194.41405600838334) rotate(0 57 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">current stock</text></g><g transform="translate(1159.7142857142858 183.41405600838334) rotate(0 49.370370370370324 25)"><path d="M0 0 C20.526187548641513 0, 41.052375097283026 0, 98.74074074074065 0 M0 0 C33.9206452924413 0, 67.8412905848826 0, 98.74074074074065 0 M98.74074074074065 0 C98.74074074074065 15.900936177931726, 98.74074074074065 31.801872355863452, 98.74074074074065 50 M98.74074074074065 0 C98.74074074074065 17.552169584669176, 98.74074074074065 35.10433916933835, 98.74074074074065 50 M98.74074074074065 50 C77.60304118323788 50, 56.465341625735114 50, 0 50 M98.74074074074065 50 C65.00140776341016 50, 31.262074786079666 50, 0 50 M0 50 C0 34.59016109351069, 0 19.18032218702137, 0 0 M0 50 C0 38.90304414089769, 0 27.806088281795382, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1195.3068783068784 196.91405600838334) rotate(0 11 11.5)"><text x="11" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">15</text></g><g transform="translate(908.6428571428569 628.8069131512407) rotate(0 412 199)"><path d="M0 0 C171.06364584192636 0, 342.1272916838527 0, 824 0 M0 0 C255.8546619512141 0, 511.7093239024282 0, 824 0 M824 0 C824 81.9858877783641, 824 163.9717755567282, 824 397.9999999999999 M824 0 C824 144.49592706207184, 824 288.9918541241437, 824 397.9999999999999 M824 397.9999999999999 C531.5596520878374 397.9999999999999, 239.11930417567487 397.9999999999999, 0 397.9999999999999 M824 397.9999999999999 C640.076900806278 397.9999999999999, 456.153801612556 397.9999999999999, 0 397.9999999999999 M0 397.9999999999999 C0 254.37236361447714, 0 110.74472722895439, 0 0 M0 397.9999999999999 C0 268.26489560361944, 0 138.529791207239, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1001.6428571428569 698.8069131512407) rotate(0 25 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Stock</text></g><g transform="translate(1020.6428571428569 753.3069131512407) rotate(0 57 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">current stock</text></g><g transform="translate(1027.6428571428569 833.9735798179072) rotate(0 54 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">next restock</text></g><g transform="translate(1207.6428571428569 838.9735798179072) rotate(0 50 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">15/02/2021</text></g><g transform="translate(1160.6428571428569 827.4735798179072) rotate(0 94.5 23)"><path d="M0 0 C49.514051240589474 0, 99.02810248117895 0, 189 0 M0 0 C62.65167563119903 0, 125.30335126239807 0, 189 0 M189 0 C189 11.8154281610623, 189 23.6308563221246, 189 46 M189 0 C189 13.85625107046217, 189 27.71250214092434, 189 46 M189 46 C139.20686839828267 46, 89.41373679656535 46, 0 46 M189 46 C135.00017379960045 46, 81.0003475992009 46, 0 46 M0 46 C0 35.174531353078784, 0 24.349062706157564, 0 0 M0 46 C0 35.074815454520284, 0 24.14963090904057, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1504.0367965367964 832.2565512018541) rotate(0 42.85000000000002 19.5)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.5074106075470783 4.36293480719127, 3.276278039155605 2.328085597306652, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.2573088406609494 4.650643978407226, 2.776074505383347 2.903503939738564, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C3.3959154886861533 8.287470801869468, 6.658685596504696 4.5340831498099305, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C3.647507052907955 7.998047814865392, 7.161868724948299 3.955237175801777, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C5.4980046620184115 11.966306174529965, 11.124320767230662 5.493969878055035, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C4.42039580787412 13.205953355679192, 8.969103058942078 7.973264240353487, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C6.6630406266275335 16.72309795439064, 13.059790491519845 9.36447900092326, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C6.7918771398395315 16.574888499895042, 13.31746351794384 9.068060091932072, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C7.53269558237936 21.819686714933805, 15.060557227084947 13.159872504933709, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C9.336812067357375 19.74428810766848, 18.668790197040977 9.00907529040306, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C6.6674860457231295 28.912008778352718, 13.591594977833937 20.94673261469564, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C11.063083258220995 23.855452614226436, 22.38278940282967 10.833620286443082, 31.89026953414718 -0.10348448890603734 M2.1061564055129054 40.256230638194594 C14.323628940968602 26.201636217315997, 26.5411014764243 12.1470417964374, 36.877284942009794 0.25662288638767805 M2.1061564055129054 40.256230638194594 C11.888797744895843 29.002589102194243, 21.67143908427878 17.748947566193888, 36.877284942009794 0.25662288638767805 M7.093171813375516 40.6163380134883 C20.458527636515843 25.241254923280316, 33.82388345965617 9.866171833072332, 42.520359378862906 -0.13797931854138312 M7.093171813375516 40.6163380134883 C19.6486159863538 26.172951698266964, 32.20406015933209 11.729565383045628, 42.520359378862906 -0.13797931854138312 M12.736246250228632 40.221735808559245 C25.559914321986906 25.469793194119767, 38.38358239374518 10.717850579680285, 47.50737478672552 0.22212805675232872 M12.736246250228632 40.221735808559245 C22.845389402126045 28.59249690254184, 32.95453255402346 16.963257996524433, 47.50737478672552 0.22212805675232872 M17.723261658091243 40.58184318385296 C27.17710913200512 29.706435723176284, 36.630956605918996 18.83102826249961, 53.15044922357863 -0.1724741481767289 M17.723261658091243 40.58184318385296 C28.21692052825332 28.510269543463995, 38.71057939841539 16.43869590307503, 53.15044922357863 -0.1724741481767289 M22.710277065953854 40.941950559146676 C31.542013545691002 30.782199931955766, 40.37375002542815 20.622449304764856, 58.13746463144125 0.1876332271169865 M22.710277065953854 40.941950559146676 C34.79887591425044 27.035608356498003, 46.88747476254703 13.12926615384933, 58.13746463144125 0.1876332271169865 M28.353351502806966 40.54734835421761 C35.54102822993252 32.27887212601467, 42.72870495705808 24.010395897811723, 63.78053906829436 -0.20696897781207468 M28.353351502806966 40.54734835421761 C40.35904046007414 26.73638307085531, 52.36472941734131 12.92541778749301, 63.78053906829436 -0.20696897781207468 M33.34036691066958 40.90745572951133 C43.7970188346571 28.878453710849296, 54.25367075864462 16.849451692187266, 68.76755447615697 0.1531383974816336 M33.34036691066958 40.90745572951133 C41.24319660752628 31.81629011859939, 49.14602630438298 22.725124507687454, 68.76755447615697 0.1531383974816336 M38.98344134752269 40.51285352458227 C47.70826425099851 30.47609289782541, 56.43308715447433 20.43933227106855, 74.41062891301009 -0.2414638074474169 M38.98344134752269 40.51285352458227 C50.55418139142306 27.20223972991225, 62.12492143532342 13.891625935242235, 74.41062891301009 -0.2414638074474169 M43.97045675538531 40.872960899875984 C54.63078229458096 28.609659188894028, 65.2911078337766 16.346357477912075, 79.3976443208727 0.11864356784629138 M43.97045675538531 40.872960899875984 C53.15853815763985 30.30328233174744, 62.3466195598944 19.7336037636189, 79.3976443208727 0.11864356784629138 M49.613531192238426 40.47835869494692 C60.24594347822508 28.24716750859936, 70.87835576421173 16.0159763222518, 85.04071875772581 -0.27595863708276624 M49.613531192238426 40.47835869494692 C59.758081658722524 28.80838833284445, 69.90263212520662 17.138417970741987, 85.04071875772581 -0.27595863708276624 M54.60054660010103 40.838466070240635 C63.07351194298503 31.091434424308353, 71.54647728586903 21.344402778376075, 88.0595570786169 2.348277478879261 M54.60054660010103 40.838466070240635 C61.491216262386075 32.91165738615166, 68.38188592467111 24.984848702062685, 88.0595570786169 2.348277478879261 M60.24362103695415 40.44386386531157 C66.15965410531828 33.638246327390696, 72.07568717368243 26.832628789469823, 88.45415928354596 7.991351915732373 M60.24362103695415 40.44386386531157 C69.49393434923996 29.802595673962045, 78.74424766152576 19.161327482612517, 88.45415928354596 7.991351915732373 M65.23063644481675 40.80397124060529 C70.53531559049588 34.70163594097189, 75.839994736175 28.599300641338488, 88.19270245948451 14.389135932808273 M65.23063644481675 40.80397124060529 C73.30286312200644 31.517936695239655, 81.37508979919612 22.23190214987402, 88.19270245948451 14.389135932808273 M70.87371088166988 40.40936903567623 C75.35165630103094 35.25808209598322, 79.82960172039202 30.10679515629021, 87.93124563542307 20.786919949884158 M70.87371088166988 40.40936903567623 C76.73927055609427 33.66181449554887, 82.60483023051864 26.9142599554215, 87.93124563542307 20.786919949884158 M75.8607262895325 40.76947641096994 C79.66673358224277 36.39116586378327, 83.47274087495305 32.0128553165966, 88.32584784035213 26.429994386737274 M75.8607262895325 40.76947641096994 C78.5739796905923 37.64823541760579, 81.2872330916521 34.52699442424164, 88.32584784035213 26.429994386737274 M81.5038007263856 40.374874206040886 C83.39465042796638 38.19970044653909, 85.28550012954716 36.02452668703729, 88.06439101629068 32.82777840381317 M81.5038007263856 40.374874206040886 C83.53537583556748 38.037814383541495, 85.56695094474935 35.7007545610421, 88.06439101629068 32.82777840381317" stroke="#fa5252" stroke-width="0.5" fill="none"></path><path d="M0 0 C27.382204342065425 0, 54.76440868413085 0, 85.70000000000013 0 M0 0 C32.83631051179958 0, 65.67262102359916 0, 85.70000000000013 0 M85.70000000000013 0 C85.70000000000013 10.997829736489804, 85.70000000000013 21.995659472979607, 85.70000000000013 39 M85.70000000000013 0 C85.70000000000013 11.259689829032869, 85.70000000000013 22.519379658065738, 85.70000000000013 39 M85.70000000000013 39 C64.52176900905567 39, 43.343538018111204 39, 0 39 M85.70000000000013 39 C67.73251752677383 39, 49.76503505354754 39, 0 39 M0 39 C0 27.597405128460377, 0 16.194810256920753, 0 0 M0 39 C0 27.376256355363875, 0 15.75251271072775, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1518.1367965367963 840.0565512018541) rotate(0 25 11.5)"><text x="25" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">never</text></g><g transform="translate(999.37012987013 903.4373024460815) rotate(0 288.49999999999994 28.5)"><path d="M0 0 C221.61191750867292 0, 443.22383501734583 0, 576.9999999999999 0 M0 0 C148.48949075983836 0, 296.9789815196767 0, 576.9999999999999 0 M576.9999999999999 0 C576.9999999999999 18.23236775575206, 576.9999999999999 36.46473551150412, 576.9999999999999 57 M576.9999999999999 0 C576.9999999999999 20.396188223082575, 576.9999999999999 40.79237644616515, 576.9999999999999 57 M576.9999999999999 57 C347.06813987987107 57, 117.13627975974231 57, 0 57 M576.9999999999999 57 C383.78149965358887 57, 190.5629993071779 57, 0 57 M0 57 C0 45.01051211776212, 0 33.02102423552424, 0 0 M0 57 C0 37.25637744097039, 0 17.51275488194078, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1494.3701298701299 903.4373024460815) rotate(0 41 29)"><path d="M0 0 C24.34247198160738 0, 48.68494396321476 0, 82 0 M0 0 C16.84486520532519 0, 33.68973041065038 0, 82 0 M82 0 C82 23.11392058711499, 82 46.22784117422998, 82 58 M82 0 C82 13.750576350279154, 82 27.501152700558308, 82 58 M82 58 C62.860811912454665 58, 43.72162382490933 58, 0 58 M82 58 C56.11744595523923 58, 30.234891910478467 58, 0 58 M0 58 C0 44.30942313093692, 0 30.61884626187384, 0 0 M0 58 C0 36.32924136202782, 0 14.658482724055645, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(1533.3701298701299 915.4373024460815) rotate(0 0 17)"><path d="M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34 M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1533.3701298701299 915.4373024460815) rotate(0 0 17)"><path d="M-5.814342436536368 18.025225446639556 C-3.6026222832168626 24.101876626037612, -1.3909021298973574 30.17852780543567, 0 34 M-5.814342436536368 18.025225446639556 C-3.699884998619726 23.834649511713405, -1.585427560703084 29.644073576787253, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1533.3701298701299 915.4373024460815) rotate(0 0 17)"><path d="M5.814342436536368 18.025225446639556 C3.6026222832168626 24.101876626037612, 1.3909021298973574 30.17852780543567, 0 34 M5.814342436536368 18.025225446639556 C3.699884998619726 23.834649511713405, 1.585427560703084 29.644073576787253, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(1030.3560452925694 919.4373024460815) rotate(0 35.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">address</text></g><g transform="translate(979.594140530665 313.37777863655765) rotate(0 288.49999999999994 28.5)"><path d="M0 0 C183.09519919259472 0, 366.19039838518944 0, 576.9999999999999 0 M0 0 C191.24218815611673 0, 382.48437631223345 0, 576.9999999999999 0 M576.9999999999999 0 C576.9999999999999 21.60299933133647, 576.9999999999999 43.20599866267294, 576.9999999999999 57 M576.9999999999999 0 C576.9999999999999 18.814047324378045, 576.9999999999999 37.62809464875609, 576.9999999999999 57 M576.9999999999999 57 C375.89746348159383 57, 174.79492696318772 57, 0 57 M576.9999999999999 57 C408.40211005760347 57, 239.80422011520704 57, 0 57 M0 57 C0 39.55012987079098, 0 22.100259741581972, 0 0 M0 57 C0 34.29172115949913, 0 11.583442318998273, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1474.5941405306648 313.37777863655765) rotate(0 41 29)"><path d="M0 0 C23.301106604374947 0, 46.602213208749895 0, 82 0 M0 0 C20.47363549526781 0, 40.94727099053562 0, 82 0 M82 0 C82 17.889156678505245, 82 35.77831335701049, 82 58 M82 0 C82 14.935910755209626, 82 29.871821510419252, 82 58 M82 58 C53.102421215735376 58, 24.20484243147075 58, 0 58 M82 58 C60.69060039464384 58, 39.38120078928768 58, 0 58 M0 58 C0 35.32809809129685, 0 12.656196182593703, 0 0 M0 58 C0 39.14703913349658, 0 20.29407826699316, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(1513.5941405306648 325.37777863655765) rotate(0 0 17)"><path d="M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34 M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1513.5941405306648 325.37777863655765) rotate(0 0 17)"><path d="M-5.814342436536368 18.025225446639556 C-4.189382644804416 22.489765781944783, -2.5644228530724638 26.954306117250006, 0 34 M-5.814342436536368 18.025225446639556 C-4.477115144868706 21.699227235174916, -3.1398878532010444 25.37322902371028, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1513.5941405306648 325.37777863655765) rotate(0 0 17)"><path d="M5.814342436536368 18.025225446639556 C4.189382644804416 22.489765781944783, 2.5644228530724638 26.954306117250006, 0 34 M5.814342436536368 18.025225446639556 C4.477115144868706 21.699227235174916, 3.1398878532010444 25.37322902371028, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(1010.5800559531045 329.37777863655765) rotate(0 35.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">address</text></g><g transform="translate(911.0870972286061 1169.8355253211091) rotate(0 412 210.2500000000001)"><path d="M0 0 C218.95360033735636 0, 437.9072006747127 0, 824 0 M0 0 C209.57695072665814 0, 419.1539014533163 0, 824 0 M824 0 C824 105.35239861519078, 824 210.70479723038156, 824 420.5 M824 0 C824 150.35835648789072, 824 300.71671297578143, 824 420.5 M824 420.5 C503.3142883516848 420.5, 182.62857670336962 420.5, 0 420.5 M824 420.5 C525.6960808418692 420.5, 227.3921616837382 420.5, 0 420.5 M0 420.5 C0 301.00011278777384, 0 181.50022557554766, 0 0 M0 420.5 C0 277.7357025532517, 0 134.97140510650348, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1004.0870972286061 1239.8355253211091) rotate(0 25 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Stock</text></g><g transform="translate(1003.0870972286061 1294.3355253211091) rotate(0 57 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">current stock</text></g><g transform="translate(1015.4669520449852 1414.5492479492834) rotate(0 288.5 28.499999999999886)"><path d="M0 0 C191.88294327305627 0, 383.76588654611254 0, 576.9999999999999 0 M0 0 C153.981226036977 0, 307.962452073954 0, 576.9999999999999 0 M576.9999999999999 0 C576.9999999999999 18.94759962530807, 576.9999999999999 37.89519925061614, 576.9999999999999 57 M576.9999999999999 0 C576.9999999999999 16.581719528418034, 576.9999999999999 33.16343905683607, 576.9999999999999 57 M576.9999999999999 57 C420.6865388090721 57, 264.37307761814435 57, 0 57 M576.9999999999999 57 C439.98495214777057 57, 302.96990429554126 57, 0 57 M0 57 C0 38.82633978752419, 0 20.65267957504838, 0 0 M0 57 C0 39.23593317987397, 0 21.471866359747942, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1510.4669520449852 1414.5492479492834) rotate(0 41 28.999999999999886)"><path d="M0 0 C20.85595868881792 0, 41.71191737763584 0, 82 0 M0 0 C20.54434408191592 0, 41.08868816383184 0, 82 0 M82 0 C82 20.739083653502167, 82 41.478167307004334, 82 58 M82 0 C82 22.57253795582801, 82 45.14507591165602, 82 58 M82 58 C52.31441581193357 58, 22.62883162386715 58, 0 58 M82 58 C58.69681153055281 58, 35.39362306110561 58, 0 58 M0 58 C0 38.30837276596576, 0 18.616745531931514, 0 0 M0 58 C0 42.259131410531694, 0 26.518262821063395, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(1549.4669520449852 1426.5492479492834) rotate(0 0 16.999999999999886)"><path d="M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34 M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1549.4669520449852 1426.5492479492834) rotate(0 0 16.999999999999886)"><path d="M-5.814342436536368 18.025225446639556 C-4.113869358350213 22.697236831346512, -2.4133962801640587 27.369248216053464, 0 34 M-5.814342436536368 18.025225446639556 C-4.337132291635999 22.083826963542613, -2.85992214673563 26.142428480445666, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1549.4669520449852 1426.5492479492834) rotate(0 0 16.999999999999886)"><path d="M5.814342436536368 18.025225446639556 C4.113869358350213 22.697236831346512, 2.4133962801640587 27.369248216053464, 0 34 M5.814342436536368 18.025225446639556 C4.337132291635999 22.083826963542613, 2.85992214673563 26.142428480445666, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(1046.4528674674248 1430.5492479492832) rotate(0 35.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">address</text></g><g transform="translate(1412.0870972286057 122.20172403965671) rotate(0 83.875 26.5)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.7173956115841835 4.121374692556808, 3.6962480472298154 1.8449653680377276, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.53886432158337 4.326751448274156, 3.339185467228188 2.2557188794724237, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C3.454961933751928 8.219545636907089, 6.776778486636245 4.398232819885173, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C2.266605675249538 9.586593133211604, 4.400065969631465 7.1323278124942, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C5.998957222391963 11.390026175559758, 12.126225887977766 4.341409880114616, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C5.228720528642109 12.276082134131954, 10.585752500478057 6.1135217972590095, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C7.703031796699608 15.52672496855091, 15.139772831663993 6.971733029243808, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C5.370490594102075 18.21000667656041, 10.474690426468928 12.33829644526281, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C7.3456726381002575 22.034832001457943, 14.686511338526742 13.59016307798198, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C9.026548904733454 20.101205047875514, 18.048263871793136 9.722909170817125, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C9.850964347063032 25.24983591541769, 19.958551580513742 13.622386888825588, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C9.221483318128827 25.973971004048572, 18.699589522645333 15.07065706608735, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C13.353319137344942 27.317849960621473, 26.5686589561485 12.11534054238004, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C12.917833983670329 27.818818323222533, 25.697688648799275 13.11727726758216, 36.877284942009794 0.25662288638767805 M-0.12347750552006431 48.9181433959388 C10.175775454041249 37.07020817328198, 20.475028413602562 25.222272950625165, 42.520359378862906 -0.13797931854138312 M-0.12347750552006431 48.9181433959388 C9.746254045955597 37.5643160313688, 19.61598559743126 26.210488666798796, 42.520359378862906 -0.13797931854138312 M0.9271837283995019 53.806508252569145 C18.728587858763337 33.32833533682499, 36.52999198912717 12.850162421080846, 47.50737478672552 0.22212805675232872 M0.9271837283995019 53.806508252569145 C16.271137215299515 36.155308919370725, 31.615090702199527 18.504109586172298, 47.50737478672552 0.22212805675232872 M5.914199136262113 54.16661562786285 C23.49673440300238 33.94022253815562, 41.07926966974265 13.713829448448386, 53.15044922357863 -0.1724741481767289 M5.914199136262113 54.16661562786285 C22.864289477153022 34.66776720015996, 39.81437981804393 15.168918772457062, 53.15044922357863 -0.1724741481767289 M11.557273573115229 53.772013422933796 C22.848484740685947 40.7829608164994, 34.13969590825667 27.79390821006499, 58.13746463144125 0.1876332271169865 M11.557273573115229 53.772013422933796 C27.778619477682486 35.111489571715715, 43.99996538224974 16.450965720497635, 58.13746463144125 0.1876332271169865 M16.544288980977836 54.13212079822751 C27.664794442473266 41.33944264299447, 38.78529990396869 28.546764487761436, 63.78053906829436 -0.20696897781207468 M16.544288980977836 54.13212079822751 C31.45706359913156 36.976936013496115, 46.36983821728528 19.82175122876471, 63.78053906829436 -0.20696897781207468 M22.18736341783096 53.73751859329845 C35.13162478449539 38.84684926227623, 48.075886151159835 23.956179931254013, 68.76755447615697 0.1531383974816336 M22.18736341783096 53.73751859329845 C33.69096689012845 40.504136589569505, 45.19457036242595 27.27075458584056, 68.76755447615697 0.1531383974816336 M27.174378825693566 54.09762596859217 C43.810054153418044 34.96047063879192, 60.44572948114252 15.82331530899166, 74.41062891301009 -0.2414638074474169 M27.174378825693566 54.09762596859217 C44.820114437100386 33.798529199055054, 62.46585004850721 13.499432429517938, 74.41062891301009 -0.2414638074474169 M32.817453262546685 53.703023763663104 C49.97269154179106 33.968179628871866, 67.12792982103542 14.23333549408062, 79.3976443208727 0.11864356784629138 M32.817453262546685 53.703023763663104 C49.16607414542128 34.89608679837052, 65.51469502829588 16.089149833077933, 79.3976443208727 0.11864356784629138 M37.80446867040929 54.06313113895682 C53.664216718620374 35.81857803780972, 69.52396476683145 17.574024936662624, 85.04071875772581 -0.27595863708276624 M37.80446867040929 54.06313113895682 C53.71031346445203 35.76554979772929, 69.61615825849475 17.467968456501765, 85.04071875772581 -0.27595863708276624 M43.447543107262405 53.668528934027755 C54.41543216278025 41.05141587065494, 65.38332121829811 28.43430280728213, 90.02773416558841 0.08414873821094204 M43.447543107262405 53.668528934027755 C60.61312426753425 33.92178667566286, 77.7787054278061 14.175044417297954, 90.02773416558841 0.08414873821094204 M48.43455851512502 54.02863630932147 C66.93170216944668 32.750106625561266, 85.42884582376834 11.471576941801061, 95.67080860244155 -0.3104534667181156 M48.43455851512502 54.02863630932147 C59.88172162803239 40.86018151192713, 71.32888474093976 27.69172671453279, 95.67080860244155 -0.3104534667181156 M54.07763295197813 53.63403410439241 C70.07482934877166 35.23136476541137, 86.07202574556518 16.828695426430336, 100.65782401030415 0.049653908575599814 M54.07763295197813 53.63403410439241 C67.6147605641235 38.0613501748612, 81.15188817626887 22.488666245329977, 100.65782401030415 0.049653908575599814 M59.064648359840746 53.99414147968613 C69.32977228979794 42.185467214455, 79.59489621975513 30.37679294922387, 106.30089844715727 -0.3449482963534578 M59.064648359840746 53.99414147968613 C71.3619643394091 39.84769768317661, 83.65928031897745 25.701253886667097, 106.30089844715727 -0.3449482963534578 M64.70772279669386 53.59953927475706 C83.26681476468622 32.24974620806945, 101.82590673267859 10.899953141381843, 111.28791385501988 0.015159078940250481 M64.70772279669386 53.59953927475706 C78.26906752069534 37.99899674483243, 91.83041224469684 22.398454214907797, 111.28791385501988 0.015159078940250481 M69.69473820455647 53.959646650050786 C83.79703187510646 37.73681354209728, 97.89932554565644 21.513980434143782, 116.2749292628825 0.375266454233973 M69.69473820455647 53.959646650050786 C88.0232089730638 32.87515292528618, 106.35167974157113 11.790659200521574, 116.2749292628825 0.375266454233973 M75.3378126414096 53.56504444512172 C86.93044099155067 40.22925103446481, 98.52306934169175 26.8934576238079, 121.9180036997356 -0.019335750695091747 M75.3378126414096 53.56504444512172 C85.89947527144335 41.415241427804126, 96.46113790147712 29.265438410486535, 121.9180036997356 -0.019335750695091747 M80.3248280492722 53.92515182041544 C91.03408820637159 41.605557270977584, 101.74334836347099 29.285962721539736, 126.9050191075982 0.34077162459862365 M80.3248280492722 53.92515182041544 C97.90171544146804 33.70525586715205, 115.4786028336639 13.485359913888658, 126.9050191075982 0.34077162459862365 M85.96790248612533 53.53054961548638 C103.91797705566042 32.88135092343194, 121.8680516251955 12.23215223137749, 132.54809354445132 -0.05383058033042687 M85.96790248612533 53.53054961548638 C101.66089334007648 35.477828722292706, 117.35388419402764 17.425107829099034, 132.54809354445132 -0.05383058033042687 M90.95491789398793 53.89065699078009 C108.32841377881171 33.90473620189459, 125.70190966363549 13.9188154130091, 137.53510895231395 0.3062767949632672 M90.95491789398793 53.89065699078009 C108.67003675500621 33.511743922899626, 126.38515561602449 13.132830855019158, 137.53510895231395 0.3062767949632672 M96.59799233084104 53.49605478585103 C107.80858362942544 40.59974472969279, 119.01917492800983 27.703434673534552, 143.17818338916706 -0.0883254099657762 M96.59799233084104 53.49605478585103 C112.61753868732575 35.0676747593386, 128.63708504381046 16.639294732826166, 143.17818338916706 -0.0883254099657762 M101.58500773870365 53.85616216114475 C120.14001076986757 32.511072878203706, 138.69501380103148 11.165983595262652, 148.16519879702966 0.2717819653279321 M101.58500773870365 53.85616216114475 C115.72587718093787 37.588952704161514, 129.8667466231721 21.321743247178283, 148.16519879702966 0.2717819653279321 M107.22808217555678 53.46155995621568 C120.72671425385484 37.93316007264153, 134.2253463321529 22.404760189067368, 153.8082732338828 -0.12282023960112554 M107.22808217555678 53.46155995621568 C123.66510766343758 34.55292512627111, 140.10213315131838 15.644290296326545, 153.8082732338828 -0.12282023960112554 M112.21509758341939 53.8216673315094 C129.19705003766725 34.28616573521338, 146.1790024919151 14.750664138917358, 158.7952886417454 0.23728713569258275 M112.21509758341939 53.8216673315094 C125.31139171728925 38.75610430823168, 138.4076858511591 23.690541284953955, 158.7952886417454 0.23728713569258275 M117.20211299128198 54.181774706803104 C133.7292754332167 35.169449172591754, 150.25643787515145 16.157123638380398, 164.4383630785985 -0.15731506923647487 M117.20211299128198 54.181774706803104 C133.81536100577716 35.0704190496007, 150.42860902027232 15.959063392398306, 164.4383630785985 -0.15731506923647487 M122.8451874281351 53.78717250187405 C133.05985181490902 42.036545300963766, 143.27451620168293 30.285918100053483, 168.7693194574706 0.9575018862800135 M122.8451874281351 53.78717250187405 C140.28991833384504 33.71930519547341, 157.73464923955493 13.651437889072767, 168.7693194574706 0.9575018862800135 M127.83220283599772 54.14727987716777 C139.23328157673114 41.03183908558893, 150.6343603174646 27.916398294010087, 168.50786263340916 7.355285903355906 M127.83220283599772 54.14727987716777 C140.48760654926735 39.58890326479492, 153.143010262537 25.030526652422076, 168.50786263340916 7.355285903355906 M133.47527727285083 53.752677672238704 C144.62918479252608 40.92157484453947, 155.7830923122013 28.09047201684024, 168.90246483833823 12.998360340209018 M133.47527727285083 53.752677672238704 C144.07958096052596 41.55382172935999, 154.6838846482011 29.354965786481277, 168.90246483833823 12.998360340209018 M138.46229268071346 54.11278504753242 C146.9895790886307 44.30326416453928, 155.51686549654798 34.493743281546145, 168.6410080142768 19.39614435728491 M138.46229268071346 54.11278504753242 C147.05382327377777 44.229359683598474, 155.64535386684204 34.34593431966452, 168.6410080142768 19.39614435728491 M144.10536711756657 53.718182842603355 C151.0098749112423 45.77545520934758, 157.91438270491798 37.83272757609179, 169.03561021920584 25.03921879413801 M144.10536711756657 53.718182842603355 C150.88646680478465 45.91741999621139, 157.66756649200275 38.11665714981944, 169.03561021920584 25.03921879413801 M149.09238252542917 54.07829021789707 C153.03681122133102 49.54074406159562, 156.98123991723287 45.003197905294165, 168.7741533951444 31.437002811213915 M149.09238252542917 54.07829021789707 C155.1688205945165 47.088147834783996, 161.2452586636038 40.098005451670915, 168.7741533951444 31.437002811213915 M154.73545696228229 53.68368801296802 C159.36574426257135 48.35715178635883, 163.9960315628604 43.03061555974963, 168.51269657108293 37.83478682828981 M154.73545696228229 53.68368801296802 C159.73862405330902 47.928202655403005, 164.74179114433576 42.172717297838, 168.51269657108293 37.83478682828981 M159.72247237014489 54.04379538826172 C161.7409058583154 51.721853271393485, 163.7593393464859 49.39991115452525, 168.907298776012 43.47786126514291 M159.72247237014489 54.04379538826172 C162.50026141307723 50.848314631347684, 165.27805045600957 47.65283387443364, 168.907298776012 43.47786126514291 M165.36554680699803 53.64919318333267 C166.0601001263845 52.850200987579996, 166.75465344577094 52.05120879182733, 168.64584195195056 49.875645282218805 M165.36554680699803 53.64919318333267 C166.5819819107356 52.24984467055833, 167.79841701447322 50.850496157783994, 168.64584195195056 49.875645282218805" stroke="#fa5252" stroke-width="0.5" fill="none"></path><path d="M0 0 C46.183000835520254 0, 92.36600167104051 0, 167.7500000000001 0 M0 0 C36.24056315112396 0, 72.48112630224792 0, 167.7500000000001 0 M167.7500000000001 0 C167.7500000000001 18.842396629508585, 167.7500000000001 37.68479325901717, 167.7500000000001 53 M167.7500000000001 0 C167.7500000000001 16.167132444027814, 167.7500000000001 32.33426488805563, 167.7500000000001 53 M167.7500000000001 53 C102.15453257735359 53, 36.55906515470707 53, 0 53 M167.7500000000001 53 C129.04311365347831 53, 90.33622730695649 53, 0 53 M0 53 C0 38.442475789133454, 0 23.884951578266914, 0 0 M0 53 C0 40.237482499238105, 0 27.474964998476207, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1442.0870972286054 137.2017240396567) rotate(0 58 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">without stock</text></g><g transform="translate(1412.0870972286061 1209.701724039657) rotate(0 79.5 26.5)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.6763342954413682 4.168610333406417, 3.614125414944185 1.9394366497369457, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.1857802863737288 4.732928167473438, 2.633017396808906 3.068072317870987, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C2.349949477829196 9.4907170557863, 4.566753574790781 6.940575657643593, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C2.9945686047466356 8.749167577490088, 5.85599182862566 5.457476701051167, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C5.2124176579807555 12.294836441487785, 10.55314675915535 6.151030411970671, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C4.955555809340896 12.590322197183463, 10.039423061875631 6.742001923362029, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C6.076761123300264 17.397535372819554, 11.887231484865305 10.713353837781092, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C6.779310011319332 16.589345327514167, 13.292329260903442 9.096973747170317, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C10.242782297882494 18.70208857658965, 20.480730658091215 6.924676228245396, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C7.852918654132539 21.451312209925682, 15.701003370591305 12.423123494917462, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C11.518475193802992 23.331584118629685, 23.293573273993662 9.785883295249576, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C6.37849692552965 29.24445273225389, 13.013616737446979 21.61162052249799, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C14.51001094359821 25.987228249816308, 28.882042568655038 9.45409712076971, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C13.87108758374623 26.722225497625526, 27.604195848951075 10.924091616388147, 36.877284942009794 0.25662288638767805 M-0.12347750552006431 48.9181433959388 C9.59161271356494 37.742210534601575, 19.306702932649944 26.56627767326435, 42.520359378862906 -0.13797931854138312 M-0.12347750552006431 48.9181433959388 C10.07668795276822 37.18419530429695, 20.276853411056504 25.450247212655093, 42.520359378862906 -0.13797931854138312 M0.9271837283995019 53.806508252569145 C19.295938194460234 32.67567343481305, 37.66469266052097 11.54483861705696, 47.50737478672552 0.22212805675232872 M0.9271837283995019 53.806508252569145 C15.31044142937061 37.26046300045369, 29.693699130341717 20.714417748338235, 47.50737478672552 0.22212805675232872 M5.914199136262113 54.16661562786285 C17.356716674322968 41.00350495300532, 28.79923421238382 27.840394278147787, 53.15044922357863 -0.1724741481767289 M5.914199136262113 54.16661562786285 C16.72681856170508 41.72811984152908, 27.53943798714805 29.289624055195297, 53.15044922357863 -0.1724741481767289 M11.557273573115229 53.772013422933796 C27.133354011702025 35.853782578050385, 42.709434450288825 17.935551733166967, 58.13746463144125 0.1876332271169865 M11.557273573115229 53.772013422933796 C28.228403248938907 34.59407253118161, 44.89953292476258 15.416131639429423, 58.13746463144125 0.1876332271169865 M16.544288980977836 54.13212079822751 C31.813370743359187 36.567051531509506, 47.082452505740534 19.001982264791508, 63.78053906829436 -0.20696897781207468 M16.544288980977836 54.13212079822751 C27.78688901826427 41.198988900311456, 39.0294890555507 28.2658570023954, 63.78053906829436 -0.20696897781207468 M22.18736341783096 53.73751859329845 C37.50897302708171 36.11202295104255, 52.83058263633245 18.48652730878665, 68.76755447615697 0.1531383974816336 M22.18736341783096 53.73751859329845 C39.292479008292844 34.06033401616755, 56.39759459875472 14.383149439036657, 68.76755447615697 0.1531383974816336 M27.174378825693566 54.09762596859217 C37.44142796809184 42.286736999791636, 47.70847711049011 30.4758480309911, 74.41062891301009 -0.2414638074474169 M27.174378825693566 54.09762596859217 C39.98323217008107 39.36272574848162, 52.79208551446856 24.627825528371073, 74.41062891301009 -0.2414638074474169 M32.817453262546685 53.703023763663104 C50.442127839427194 33.42815494286845, 68.0668024163077 13.153286122073801, 79.3976443208727 0.11864356784629138 M32.817453262546685 53.703023763663104 C45.6266603288556 38.96771663302921, 58.435867395164514 24.232409502395328, 79.3976443208727 0.11864356784629138 M37.80446867040929 54.06313113895682 C47.43497861338879 42.9844967551254, 57.065488556368294 31.905862371293974, 85.04071875772581 -0.27595863708276624 M37.80446867040929 54.06313113895682 C55.52889401123652 33.673512190721695, 73.25331935206376 13.283893242486577, 85.04071875772581 -0.27595863708276624 M43.447543107262405 53.668528934027755 C55.83551580208621 39.417796516385934, 68.22348849691002 25.167064098744106, 90.02773416558841 0.08414873821094204 M43.447543107262405 53.668528934027755 C53.30706930107239 42.32644149050074, 63.166595494882365 30.98435404697373, 90.02773416558841 0.08414873821094204 M48.43455851512502 54.02863630932147 C67.0908023826447 32.567082766716126, 85.74704625016437 11.10552922411079, 95.67080860244155 -0.3104534667181156 M48.43455851512502 54.02863630932147 C64.45882481017543 35.59482661459903, 80.48309110522584 17.161016919876587, 95.67080860244155 -0.3104534667181156 M54.07763295197813 53.63403410439241 C66.08133276375455 39.82535707116004, 78.08503257553096 26.016680037927674, 100.65782401030415 0.049653908575599814 M54.07763295197813 53.63403410439241 C72.70393937857786 32.206919648014434, 91.33024580517758 10.779805191636449, 100.65782401030415 0.049653908575599814 M59.064648359840746 53.99414147968613 C70.1902433741227 41.19560846372059, 81.31583838840466 28.397075447755043, 106.30089844715727 -0.3449482963534578 M59.064648359840746 53.99414147968613 C77.69525417082781 32.562081147338446, 96.32585998181489 11.130020814990765, 106.30089844715727 -0.3449482963534578 M64.70772279669386 53.59953927475706 C74.13910111598257 42.74997961969814, 83.5704794352713 31.90041996463922, 111.28791385501988 0.015159078940250481 M64.70772279669386 53.59953927475706 C76.55944342570267 39.96569429193582, 88.41116405471146 26.33184930911458, 111.28791385501988 0.015159078940250481 M69.69473820455647 53.959646650050786 C79.16741721515874 43.06257598450837, 88.64009622576101 32.16550531896595, 116.2749292628825 0.375266454233973 M69.69473820455647 53.959646650050786 C84.3289502908371 37.1249114014217, 98.96316237711773 20.290176152792604, 116.2749292628825 0.375266454233973 M75.3378126414096 53.56504444512172 C86.14180353400351 41.13647465037817, 96.94579442659742 28.70790485563462, 121.9180036997356 -0.019335750695091747 M75.3378126414096 53.56504444512172 C88.49005672829291 38.43511836351181, 101.64230081517624 23.305192281901906, 121.9180036997356 -0.019335750695091747 M80.3248280492722 53.92515182041544 C94.71918853078526 37.36633428033221, 109.11354901229831 20.807516740248992, 126.9050191075982 0.34077162459862365 M80.3248280492722 53.92515182041544 C94.9563456434856 37.09351623033399, 109.587863237699 20.261880640252535, 126.9050191075982 0.34077162459862365 M85.96790248612533 53.53054961548638 C98.10578744757035 39.56751022535702, 110.24367240901537 25.604470835227655, 132.54809354445132 -0.05383058033042687 M85.96790248612533 53.53054961548638 C103.80023219455592 33.01680089175919, 121.63256190298651 12.503052168031992, 132.54809354445132 -0.05383058033042687 M90.95491789398793 53.89065699078009 C109.39582213972629 32.67682334589489, 127.83672638546466 11.462989701009697, 137.53510895231395 0.3062767949632672 M90.95491789398793 53.89065699078009 C107.35244279276296 35.027462390609415, 123.74996769153798 16.164267790438743, 137.53510895231395 0.3062767949632672 M96.59799233084104 53.49605478585103 C109.90482235845376 38.18829792182548, 123.21165238606649 22.88054105779993, 143.17818338916706 -0.0883254099657762 M96.59799233084104 53.49605478585103 C112.77249588422322 34.88941689555622, 128.9469994376054 16.282779005261403, 143.17818338916706 -0.0883254099657762 M101.58500773870365 53.85616216114475 C112.7724984269507 40.98642631730611, 123.95998911519776 28.11669047346747, 148.16519879702966 0.2717819653279321 M101.58500773870365 53.85616216114475 C112.20006631530816 41.644934133818495, 122.81512489191269 29.433706106492235, 148.16519879702966 0.2717819653279321 M107.22808217555678 53.46155995621568 C120.61208073460944 38.06503085158998, 133.9960792936621 22.66850174696429, 153.8082732338828 -0.12282023960112554 M107.22808217555678 53.46155995621568 C123.95754253771364 34.2165172857343, 140.6870028998705 14.971474615252909, 153.8082732338828 -0.12282023960112554 M112.21509758341939 53.8216673315094 C123.90092493152434 40.3786607380102, 135.58675227962928 26.935654144510988, 158.7952886417454 0.23728713569258275 M112.21509758341939 53.8216673315094 C125.43723812719647 38.611334574112234, 138.65937867097352 23.401001816715073, 158.7952886417454 0.23728713569258275 M117.20211299128198 54.181774706803104 C130.99364885222906 38.316427565314, 144.7851847131761 22.4510804238249, 159.18989084667447 5.880361572545695 M117.20211299128198 54.181774706803104 C129.560359585114 39.96523825661208, 141.91860617894605 25.74870180642106, 159.18989084667447 5.880361572545695 M122.8451874281351 53.78717250187405 C136.18922449133777 38.43661383957947, 149.53326155454045 23.086055177284887, 158.928434022613 12.278145589621587 M122.8451874281351 53.78717250187405 C133.82487607659277 41.15648555956519, 144.80456472505045 28.525798617256328, 158.928434022613 12.278145589621587 M127.83220283599772 54.14727987716777 C135.85614577605108 44.916789417586315, 143.88008871610447 35.686298958004855, 159.32303622754208 17.921220026474714 M127.83220283599772 54.14727987716777 C134.7825839478684 46.15178102792611, 141.73296505973906 38.15628217868446, 159.32303622754208 17.921220026474714 M133.47527727285083 53.752677672238704 C142.9837100332666 42.81447702247116, 152.49214279368235 31.876276372703618, 159.0615794034806 24.319004043550592 M133.47527727285083 53.752677672238704 C138.9946597866402 47.40335440100733, 144.51404230042957 41.05403112977595, 159.0615794034806 24.319004043550592 M138.46229268071346 54.11278504753242 C146.49336568920856 44.87409238247427, 154.52443869770366 35.63539971741612, 158.80012257941917 30.716788060626484 M138.46229268071346 54.11278504753242 C144.5317253147659 47.13070149556227, 150.60115794881838 40.14861794359212, 158.80012257941917 30.716788060626484 M144.10536711756657 53.718182842603355 C149.59412307147716 47.4040913982784, 155.08287902538774 41.08999995395345, 159.19472478434824 36.3598624974796 M144.10536711756657 53.718182842603355 C149.94297087583203 47.00278790522013, 155.7805746340975 40.28739296783691, 159.19472478434824 36.3598624974796 M149.09238252542917 54.07829021789707 C151.6516127612986 51.13423260774811, 154.21084299716802 48.19017499759916, 158.9332679602868 42.75764651455549 M149.09238252542917 54.07829021789707 C151.84593396586163 50.91069163316567, 154.5994854062941 47.74309304843426, 158.9332679602868 42.75764651455549 M154.73545696228229 53.68368801296802 C156.05098012122784 52.17035173194947, 157.36650328017342 50.657015450930906, 159.32787016521584 48.400720951408616 M154.73545696228229 53.68368801296802 C156.24479352007694 51.947394921017356, 157.75413007787157 50.211101829066685, 159.32787016521584 48.400720951408616" stroke="#fa5252" stroke-width="0.5" fill="none"></path><path d="M0 0 C42.85518687916917 0, 85.71037375833833 0, 158.9999999999999 0 M0 0 C57.662035526800864 0, 115.32407105360173 0, 158.9999999999999 0 M158.9999999999999 0 C158.9999999999999 16.40436417544261, 158.9999999999999 32.80872835088522, 158.9999999999999 53 M158.9999999999999 0 C158.9999999999999 13.331009528692814, 158.9999999999999 26.662019057385628, 158.9999999999999 53 M158.9999999999999 53 C107.5467047874815 53, 56.093409574963104 53, 0 53 M158.9999999999999 53 C99.94139154357828 53, 40.88278308715668 53, 0 53 M0 53 C0 37.42691702758893, 0 21.853834055177863, 0 0 M0 53 C0 38.142077192012216, 0 23.284154384024436, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1442.0870972286061 1224.701724039657) rotate(0 58 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">without stock</text></g><g transform="translate(63.87281151432046 18.772654820766093) rotate(0 239 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"># create product without stock</text></g><g transform="translate(1402.7656686571772 674.1650017457355) rotate(0 79.5 26.5)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C0.9590294310660872 4.993775187729691, 2.1795156861936227 3.5897663583834936, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.6496073208572388 4.199356200588598, 3.560671465775926 2.000928384101308, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C2.2922858811843985 9.55705143561321, 4.451426381501186 7.073244417297413, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C3.0914745139615354 8.637690081056238, 6.04980364705546 5.234521708183471, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C3.3443144650777965 14.443843336032044, 6.816940373349432 10.449044201059191, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C5.01479641440859 12.522173676688933, 10.157904272011018 6.605704882372967, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C6.313581141842409 17.125105105291176, 12.360871521949596 10.168493302724338, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C4.782279493601126 18.886666143353406, 9.29826822546703 13.6916153788488, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C10.401758796254919 18.519207035371387, 20.798683654836065 6.5589131458088765, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C9.456501407525241 19.606601272058242, 18.90816887737671 8.733701619182579, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C9.005901199992277 26.221969861914648, 18.26842528637223 15.566654781819501, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C7.555575484081738 27.890378745678326, 15.367773854551155 18.903472549346855, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C12.642047587190632 28.136074280874105, 25.14611585583988 13.751789182885304, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C10.608185768210685 30.47576466208169, 21.078392217879987 18.431169945300475, 36.877284942009794 0.25662288638767805 M-0.12347750552006431 48.9181433959388 C14.406384704375723 32.203448948400236, 28.93624691427151 15.488754500861681, 42.520359378862906 -0.13797931854138312 M-0.12347750552006431 48.9181433959388 C9.233749970811559 38.15388452798652, 18.59097744714318 27.389625660034245, 42.520359378862906 -0.13797931854138312 M0.9271837283995019 53.806508252569145 C18.00889372145183 34.15624873525034, 35.090603714504155 14.505989217931528, 47.50737478672552 0.22212805675232872 M0.9271837283995019 53.806508252569145 C17.862422907835555 34.324744131814455, 34.797662087271604 14.842980011059765, 47.50737478672552 0.22212805675232872 M5.914199136262113 54.16661562786285 C23.081586803698528 34.41779522072842, 40.24897447113494 14.668974813593984, 53.15044922357863 -0.1724741481767289 M5.914199136262113 54.16661562786285 C24.35590728671535 32.951857196391245, 42.79761543716859 11.737098764919644, 53.15044922357863 -0.1724741481767289 M11.557273573115229 53.772013422933796 C21.88915933163768 41.886538459312895, 32.22104509016013 30.001063495691994, 58.13746463144125 0.1876332271169865 M11.557273573115229 53.772013422933796 C20.900653777763026 43.023684018852805, 30.244033982410823 32.27535461477181, 58.13746463144125 0.1876332271169865 M16.544288980977836 54.13212079822751 C33.39244654091159 34.750532621397895, 50.24060410084536 15.368944444568285, 63.78053906829436 -0.20696897781207468 M16.544288980977836 54.13212079822751 C30.442759793989424 38.14375906625568, 44.34123060700101 22.15539733428385, 63.78053906829436 -0.20696897781207468 M22.18736341783096 53.73751859329845 C40.118140206275996 33.110519458939486, 58.048916994721026 12.483520324580525, 68.76755447615697 0.1531383974816336 M22.18736341783096 53.73751859329845 C33.500898195362026 40.722785611230535, 44.81443297289309 27.708052629162626, 68.76755447615697 0.1531383974816336 M27.174378825693566 54.09762596859217 C41.51903694549283 37.59598445518877, 55.86369506529209 21.094342941785364, 74.41062891301009 -0.2414638074474169 M27.174378825693566 54.09762596859217 C39.51854700250924 39.89728488456045, 51.86271517932491 25.696943800528732, 74.41062891301009 -0.2414638074474169 M32.817453262546685 53.703023763663104 C49.97093502899642 33.970200265697684, 67.12441679544617 14.237376767732272, 79.3976443208727 0.11864356784629138 M32.817453262546685 53.703023763663104 C45.83650989757114 38.726312318909905, 58.85556653259559 23.749600874156705, 79.3976443208727 0.11864356784629138 M37.80446867040929 54.06313113895682 C50.58084181837462 39.36559511067067, 63.357214966339946 24.66805908238452, 85.04071875772581 -0.27595863708276624 M37.80446867040929 54.06313113895682 C52.652311974553655 36.982641286501135, 67.50015527869802 19.90215143404545, 85.04071875772581 -0.27595863708276624 M43.447543107262405 53.668528934027755 C53.54115053169298 42.0571618380714, 63.63475795612354 30.445794742115048, 90.02773416558841 0.08414873821094204 M43.447543107262405 53.668528934027755 C59.36198264326729 35.36106047317875, 75.27642217927217 17.053592012329744, 90.02773416558841 0.08414873821094204 M48.43455851512502 54.02863630932147 C62.885471912113616 37.40476208193895, 77.33638530910221 20.780887854556426, 95.67080860244155 -0.3104534667181156 M48.43455851512502 54.02863630932147 C61.09681455113109 39.46237700135656, 73.75907058713716 24.896117693391645, 95.67080860244155 -0.3104534667181156 M54.07763295197813 53.63403410439241 C63.76684417702619 42.48787162020596, 73.45605540207424 31.341709136019503, 100.65782401030415 0.049653908575599814 M54.07763295197813 53.63403410439241 C63.522854684102754 42.76854942455894, 72.96807641622738 31.903064744725476, 100.65782401030415 0.049653908575599814 M59.064648359840746 53.99414147968613 C75.20503992215906 35.42674494621858, 91.34543148447739 16.859348412751032, 106.30089844715727 -0.3449482963534578 M59.064648359840746 53.99414147968613 C69.90665639563773 41.52183796446898, 80.74866443143469 29.049534449251826, 106.30089844715727 -0.3449482963534578 M64.70772279669386 53.59953927475706 C81.14042862926009 34.695873639816455, 97.57313446182631 15.792208004875853, 111.28791385501988 0.015159078940250481 M64.70772279669386 53.59953927475706 C77.6778807169985 38.679079366571244, 90.64803863730316 23.758619458385425, 111.28791385501988 0.015159078940250481 M69.69473820455647 53.959646650050786 C83.30804872765351 38.299324306590634, 96.92135925075056 22.639001963130486, 116.2749292628825 0.375266454233973 M69.69473820455647 53.959646650050786 C83.57195224873057 37.9957380333892, 97.44916629290466 22.031829416727625, 116.2749292628825 0.375266454233973 M75.3378126414096 53.56504444512172 C89.05065264842965 37.79022652776953, 102.76349265544968 22.015408610417342, 121.9180036997356 -0.019335750695091747 M75.3378126414096 53.56504444512172 C90.54478350832046 36.07142559029717, 105.75175437523133 18.577806735472613, 121.9180036997356 -0.019335750695091747 M80.3248280492722 53.92515182041544 C96.85611522661567 34.908081320901715, 113.38740240395916 15.891010821388, 126.9050191075982 0.34077162459862365 M80.3248280492722 53.92515182041544 C92.6511138377993 39.745382070916534, 104.97739962632642 25.56561232141764, 126.9050191075982 0.34077162459862365 M85.96790248612533 53.53054961548638 C95.70477304283412 42.32956134184813, 105.44164359954293 31.12857306820987, 132.54809354445132 -0.05383058033042687 M85.96790248612533 53.53054961548638 C102.12242584637285 34.946896308143835, 118.27694920662037 16.363243000801297, 132.54809354445132 -0.05383058033042687 M90.95491789398793 53.89065699078009 C105.38220157030383 37.29396564753089, 119.80948524661974 20.69727430428169, 137.53510895231395 0.3062767949632672 M90.95491789398793 53.89065699078009 C105.5442524583211 37.107547425593715, 120.13358702265427 20.324437860407343, 137.53510895231395 0.3062767949632672 M96.59799233084104 53.49605478585103 C110.83845913987416 37.11427166465995, 125.07892594890727 20.732488543468875, 143.17818338916706 -0.0883254099657762 M96.59799233084104 53.49605478585103 C109.71675322390044 38.40464671258903, 122.83551411695983 23.31323863932702, 143.17818338916706 -0.0883254099657762 M101.58500773870365 53.85616216114475 C111.81690229869126 42.085713913318486, 122.04879685867887 30.315265665492223, 148.16519879702966 0.2717819653279321 M101.58500773870365 53.85616216114475 C116.46409779057373 36.739727037277, 131.3431878424438 19.623291913409247, 148.16519879702966 0.2717819653279321 M107.22808217555678 53.46155995621568 C122.42569725688868 35.97870370154591, 137.6233123382206 18.495847446876148, 153.8082732338828 -0.12282023960112554 M107.22808217555678 53.46155995621568 C121.91485115558635 36.56636491743614, 136.60162013561592 19.6711698786566, 153.8082732338828 -0.12282023960112554 M112.21509758341939 53.8216673315094 C127.60625312960151 36.116168240557066, 142.99740867578362 18.41066914960473, 158.7952886417454 0.23728713569258275 M112.21509758341939 53.8216673315094 C128.57550998385707 35.00116577693906, 144.93592238429474 16.180664222368712, 158.7952886417454 0.23728713569258275 M117.20211299128198 54.181774706803104 C127.5022841883169 42.33278317276633, 137.80245538535183 30.483791638729556, 159.18989084667447 5.880361572545695 M117.20211299128198 54.181774706803104 C132.9196815579222 36.10078038941022, 148.6372501245624 18.019786072017332, 159.18989084667447 5.880361572545695 M122.8451874281351 53.78717250187405 C136.21592740610657 38.40589565004875, 149.586667384078 23.02461879822345, 158.928434022613 12.278145589621587 M122.8451874281351 53.78717250187405 C136.1507215140126 38.48090644827832, 149.45625559989006 23.17464039468259, 158.928434022613 12.278145589621587 M127.83220283599772 54.14727987716777 C139.49335374182792 40.73266028326407, 151.1545046476581 27.31804068936036, 159.32303622754208 17.921220026474714 M127.83220283599772 54.14727987716777 C134.99547975648431 45.90687241566457, 142.15875667697094 37.66646495416138, 159.32303622754208 17.921220026474714 M133.47527727285083 53.752677672238704 C139.90777337582978 46.35293737579948, 146.3402694788087 38.95319707936025, 159.0615794034806 24.319004043550592 M133.47527727285083 53.752677672238704 C141.77271026596918 44.2075728959221, 150.0701432590875 34.6624681196055, 159.0615794034806 24.319004043550592 M138.46229268071346 54.11278504753242 C143.373776160389 48.46276961992574, 148.2852596400646 42.81275419231905, 158.80012257941917 30.716788060626484 M138.46229268071346 54.11278504753242 C146.30494626051942 45.090844140544895, 154.14759984032534 36.06890323355738, 158.80012257941917 30.716788060626484 M144.10536711756657 53.718182842603355 C149.64530062640395 47.34521835593179, 155.18523413524136 40.97225386926022, 159.19472478434824 36.3598624974796 M144.10536711756657 53.718182842603355 C148.06447503732974 49.16375017092931, 152.0235829570929 44.60931749925527, 159.19472478434824 36.3598624974796 M149.09238252542917 54.07829021789707 C152.35916932678035 50.32028188849612, 155.62595612813152 46.56227355909516, 158.9332679602868 42.75764651455549 M149.09238252542917 54.07829021789707 C151.07904965559007 51.79289111569554, 153.065716785751 49.507492013494, 158.9332679602868 42.75764651455549 M154.73545696228229 53.68368801296802 C156.08904198267132 52.12656656902486, 157.44262700306038 50.5694451250817, 159.32787016521584 48.400720951408616 M154.73545696228229 53.68368801296802 C155.7443932571591 52.523039574443125, 156.7533295520359 51.36239113591823, 159.32787016521584 48.400720951408616" stroke="#fa5252" stroke-width="0.5" fill="none"></path><path d="M0 0 C57.12026438964527 0, 114.24052877929054 0, 158.9999999999999 0 M0 0 C46.70137843983245 0, 93.4027568796649 0, 158.9999999999999 0 M158.9999999999999 0 C158.9999999999999 19.07754825735465, 158.9999999999999 38.1550965147093, 158.9999999999999 53 M158.9999999999999 0 C158.9999999999999 20.238926912005994, 158.9999999999999 40.47785382401199, 158.9999999999999 53 M158.9999999999999 53 C100.32112446175881 53, 41.64224892351773 53, 0 53 M158.9999999999999 53 C120.11725420458234 53, 81.23450840916479 53, 0 53 M0 53 C0 37.942913892026986, 0 22.885827784053976, 0 0 M0 53 C0 32.091631084028634, 0 11.183262168057261, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1432.7656686571772 689.1650017457355) rotate(0 58 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">without stock</text></g><g transform="translate(955.0750205101397 10) rotate(0 363 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"># creating product with stock: unkown restock</text></g><g transform="translate(949.3607347958546 1107.5000000000002) rotate(0 388 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"># creating product with stock: with restock never </text></g><g transform="translate(944.3607347958537 557.9401274238317) rotate(0 328 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"># creating product next restock: with date</text></g><g transform="translate(1164.0591474942667 1281.4486080177874) rotate(0 49.370370370370324 25)"><path d="M0 0 C23.45212747769911 0, 46.90425495539822 0, 98.74074074074065 0 M0 0 C20.73102883723459 0, 41.46205767446918 0, 98.74074074074065 0 M98.74074074074065 0 C98.74074074074065 15.249146842397751, 98.74074074074065 30.498293684795502, 98.74074074074065 50 M98.74074074074065 0 C98.74074074074065 16.16197635885328, 98.74074074074065 32.32395271770656, 98.74074074074065 50 M98.74074074074065 50 C60.310699718686934 50, 21.88065869663322 50, 0 50 M98.74074074074065 50 C76.67712927301304 50, 54.613517805285426 50, 0 50 M0 50 C0 36.00903776939958, 0 22.018075538799163, 0 0 M0 50 C0 36.17254475597292, 0 22.345089511945844, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1199.6517400868593 1294.9486080177874) rotate(0 11 11.5)"><text x="11" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">15</text></g><g transform="translate(1164.5591474942662 741.9486080177871) rotate(0 49.370370370370324 25)"><path d="M0 0 C36.75340074836791 0, 73.50680149673582 0, 98.74074074074065 0 M0 0 C27.905231700830686 0, 55.81046340166137 0, 98.74074074074065 0 M98.74074074074065 0 C98.74074074074065 10.219821208156645, 98.74074074074065 20.43964241631329, 98.74074074074065 50 M98.74074074074065 0 C98.74074074074065 19.624865702353418, 98.74074074074065 39.249731404706836, 98.74074074074065 50 M98.74074074074065 50 C63.61054871782516 50, 28.480356694909673 50, 0 50 M98.74074074074065 50 C59.59350222807924 50, 20.446263715417828 50, 0 50 M0 50 C0 37.69948286470026, 0 25.398965729400512, 0 0 M0 50 C0 35.27201617602259, 0 20.54403235204518, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1200.1517400868588 755.4486080177871) rotate(0 11 11.5)"><text x="11" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">15</text></g><g transform="translate(1814.0809814929971 1842.1071341952047) rotate(0 412 266.56944444444457)"><path d="M0 0 C274.16651551425457 0, 548.3330310285091 0, 824 0 M0 0 C297.1355347424746 0, 594.2710694849492 0, 824 0 M824 0 C824 116.17392364551009, 824 232.34784729102017, 824 533.1388888888891 M824 0 C824 179.31330792878038, 824 358.62661585756075, 824 533.1388888888891 M824 533.1388888888891 C567.5864898949861 533.1388888888891, 311.17297978997226 533.1388888888891, 0 533.1388888888891 M824 533.1388888888891 C609.0388737887145 533.1388888888891, 394.0777475774288 533.1388888888891, 0 533.1388888888891 M0 533.1388888888891 C0 356.3190921438136, 0 179.49929539873796, 0 0 M0 533.1388888888891 C0 424.3866610642214, 0 315.6344332395537, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1907.0809814929967 1912.1071341952047) rotate(0 25 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Stock</text></g><g transform="translate(1941.4976481596632 1976.507927845998) rotate(0 31 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">current</text></g><g transform="translate(1892.9034923155082 2261.8565711090932) rotate(0 288.5 28.5)"><path d="M0 0 C210.84164893589912 0, 421.68329787179823 0, 576.9999999999999 0 M0 0 C226.9310409609228 0, 453.8620819218456 0, 576.9999999999999 0 M576.9999999999999 0 C576.9999999999999 18.367664065584542, 576.9999999999999 36.735328131169084, 576.9999999999999 57 M576.9999999999999 0 C576.9999999999999 15.9439185295254, 576.9999999999999 31.8878370590508, 576.9999999999999 57 M576.9999999999999 57 C425.9349190238862 57, 274.8698380477726 57, 0 57 M576.9999999999999 57 C374.58122126422813 57, 172.16244252845638 57, 0 57 M0 57 C0 42.26120472885668, 0 27.522409457713366, 0 0 M0 57 C0 40.81852394007146, 0 24.637047880142923, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2387.903492315508 2261.8565711090932) rotate(0 41 29)"><path d="M0 0 C25.642520541697746 0, 51.28504108339549 0, 82 0 M0 0 C26.927581327408557 0, 53.855162654817114 0, 82 0 M82 0 C82 13.545655617862941, 82 27.091311235725883, 82 58 M82 0 C82 15.152590277045967, 82 30.305180554091933, 82 58 M82 58 C58.220881395787 58, 34.441762791574 58, 0 58 M82 58 C60.07624772265554 58, 38.15249544531107 58, 0 58 M0 58 C0 41.12247482761741, 0 24.244949655234812, 0 0 M0 58 C0 44.12997278943658, 0 30.259945578873158, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(2426.903492315508 2273.8565711090932) rotate(0 0 17)"><path d="M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34 M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2426.903492315508 2273.8565711090932) rotate(0 0 17)"><path d="M-5.814342436536368 18.025225446639556 C-4.643740285856778 21.241428422796748, -3.4731381351771877 24.45763139895394, 0 34 M-5.814342436536368 18.025225446639556 C-4.192122791573714 22.482237290570144, -2.5699031466110593 26.939249134500734, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2426.903492315508 2273.8565711090932) rotate(0 0 17)"><path d="M5.814342436536368 18.025225446639556 C4.643740285856778 21.241428422796748, 3.4731381351771877 24.45763139895394, 0 34 M5.814342436536368 18.025225446639556 C4.192122791573714 22.482237290570144, 2.5699031466110593 26.939249134500734, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(1923.8894077379477 2277.8565711090932) rotate(0 35.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">address</text></g><g transform="translate(2122.486963969733 1971.636797748869) rotate(0 11 11.5)"><text x="11" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">15</text></g><g transform="translate(1943.9162053758716 2213.340383000729) rotate(0 54 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">next restock</text></g><g transform="translate(2298.630491090157 2204.5546687150145) rotate(0 36 23)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.2611187238108525 4.646261209196374, 2.7836942716831534 2.8947384013168596, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.684746007607977 4.158933765479314, 3.6309488392774023 1.920083513882739, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C3.739643965731985 7.892056421213751, 7.346142550596359 3.743254388498496, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C2.495653567887535 9.3231036737803, 4.858161754907459 6.605348893631596, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C4.036540063134039 13.647528877358473, 8.201391569461917 8.85641528371205, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C4.724114151797874 12.856565368135819, 9.576539746789587 7.274488265266742, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C5.662661821618544 17.873902126926485, 11.059032881501865 11.666087345994956, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C8.512157091179688 14.59593279229763, 16.758023420624156 5.110148676737246, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C5.41527874113689 24.255496154016846, 10.825723544600008 18.031491383099794, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C9.2384643851211 19.857424174236503, 18.472094832568427 9.235347423539103, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C6.6630249272410005 28.91714070811543, 13.582672740869679 20.956996474221064, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C6.85865783887235 28.692090787162066, 13.973938564132379 20.506896632314337, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C12.757833347695543 28.0028779999832, 25.377687376849703 13.485396621103487, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C9.781914135509359 31.42628144412422, 19.425848952477335 20.332203509385533, 36.877284942009794 0.25662288638767805 M1.1886405524609494 47.40872423549325 C15.385556051510763 31.07704116540005, 29.582471550560577 14.745358095306848, 42.520359378862906 -0.13797931854138312 M1.1886405524609494 47.40872423549325 C10.468500563770826 36.73346645504877, 19.748360575080703 26.058208674604284, 42.520359378862906 -0.13797931854138312 M6.831714989314069 47.014122030564195 C23.047288933632743 28.36023806006382, 39.26286287795142 9.706354089563447, 47.50737478672552 0.22212805675232872 M6.831714989314069 47.014122030564195 C15.250952012991574 37.328897745620154, 23.67018903666908 27.643673460676105, 47.50737478672552 0.22212805675232872 M11.818730397176676 47.3742294058579 C22.597903379623546 34.974209350880756, 33.37707636207041 22.574189295903615, 53.15044922357863 -0.1724741481767289 M11.818730397176676 47.3742294058579 C25.14197529521831 32.047589393482305, 38.46522019325994 16.72094938110671, 53.15044922357863 -0.1724741481767289 M17.461804834029795 46.979627200928846 C33.226246254203865 28.844711833674296, 48.99068767437794 10.709796466419746, 58.13746463144125 0.1876332271169865 M17.461804834029795 46.979627200928846 C32.04277050544074 30.20614494576362, 46.62373617685169 13.432662690598391, 58.13746463144125 0.1876332271169865 M22.448820241892403 47.33973457622256 C34.020553773428105 34.02797790476389, 45.592287304963804 20.71622123330521, 63.78053906829436 -0.20696897781207468 M22.448820241892403 47.33973457622256 C32.413442208827774 35.87674827555963, 42.37806417576315 24.413761974896698, 63.78053906829436 -0.20696897781207468 M28.091894678745525 46.9451323712935 C37.03616338094111 36.65592823059203, 45.9804320831367 26.36672408989057, 68.76755447615697 0.1531383974816336 M28.091894678745525 46.9451323712935 C40.145889213497476 33.07859787770013, 52.199883748249434 19.212063384106777, 68.76755447615697 0.1531383974816336 M33.07891008660813 47.30523974658722 C41.38525638927088 37.749881380566954, 49.691602691933625 28.19452301454669, 73.09851085502908 1.2679553529981291 M33.07891008660813 47.30523974658722 C45.61547031299049 32.88357692693349, 58.152030539372845 18.461914107279764, 73.09851085502908 1.2679553529981291 M38.72198452346125 46.91063754165816 C49.12053993799855 34.948467912037486, 59.51909535253584 22.986298282416808, 73.49311305995813 6.911029789851241 M38.72198452346125 46.91063754165816 C45.893685857880584 38.66053890051741, 53.065387192299916 30.41044025937665, 73.49311305995813 6.911029789851241 M43.70899993132386 47.27074491695187 C53.860181013368766 35.593146904187826, 64.01136209541367 23.91554889142378, 73.23165623589668 13.30881380692713 M43.70899993132386 47.27074491695187 C51.905471129667134 37.841783399680835, 60.10194232801041 28.412821882409805, 73.23165623589668 13.30881380692713 M49.35207436817697 46.87614271202281 C56.96246633493155 38.12138822689979, 64.57285830168613 29.366633741776763, 72.97019941183524 19.706597824003016 M49.35207436817697 46.87614271202281 C55.967382671880934 39.26610103541496, 62.5826909755849 31.656059358807116, 72.97019941183524 19.706597824003016 M54.339089776039586 47.23625008731652 C59.720999826929734 41.045070794267275, 65.10290987781988 34.85389150121803, 73.3648016167643 25.34967226085613 M54.339089776039586 47.23625008731652 C59.65157792303411 41.12493155927794, 64.96406607002864 35.01361303123936, 73.3648016167643 25.34967226085613 M59.9821642128927 46.84164788238747 C63.66028229464649 42.610457043109555, 67.33840037640029 38.37926620383165, 73.10334479270284 31.747456277932027 M59.9821642128927 46.84164788238747 C64.12857415865852 42.07174887739148, 68.27498410442436 37.30184987239548, 73.10334479270284 31.747456277932027 M64.96917962075531 47.20175525768118 C67.63395468548822 44.13628221086212, 70.29872975022114 41.070809164043055, 73.49794699763191 37.39053071478514 M64.96917962075531 47.20175525768118 C67.26606697808306 44.55948860686598, 69.56295433541081 41.91722195605079, 73.49794699763191 37.39053071478514 M69.95619502861793 47.561862632974886 C70.80251865776677 46.58827866771744, 71.6488422869156 45.614694702459985, 73.23649017357046 43.78831473186103 M69.95619502861793 47.561862632974886 C71.0006149851761 46.36039491107923, 72.04503494173426 45.15892718918357, 73.23649017357046 43.78831473186103" stroke="#4c6ef5" stroke-width="0.5" fill="none"></path><path d="M0 0 C16.193762657046317 0, 32.387525314092635 0, 72 0 M0 0 C17.504456117749214 0, 35.00891223549843 0, 72 0 M72 0 C72 18.31221368983388, 72 36.62442737966776, 72 46 M72 0 C72 9.369684558361769, 72 18.739369116723537, 72 46 M72 46 C56.27316487133503 46, 40.54632974267005 46, 0 46 M72 46 C54.11647951304913 46, 36.23295902609825 46, 0 46 M0 46 C0 29.97982518002391, 0 13.959650360047817, 0 0 M0 46 C0 28.27324437573552, 0 10.546488751471038, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(25.09190430596891 1844.8671778767057) rotate(0 412 84.5)"><path d="M0 0 C167.83794610202312 0, 335.67589220404625 0, 824 0 M0 0 C257.2014637738466 0, 514.4029275476933 0, 824 0 M824 0 C824 50.912549302354456, 824 101.82509860470891, 824 169 M824 0 C824 65.41591384075582, 824 130.83182768151164, 824 169 M824 169 C620.7830524712801 169, 417.5661049425602 169, 0 169 M824 169 C523.9873734682799 169, 223.97474693655965 169, 0 169 M0 169 C0 129.2093227174133, 0 89.41864543482662, 0 0 M0 169 C0 116.37540726996957, 0 63.75081453993916, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(118.09190430596891 1914.8671778767057) rotate(0 25 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Stock</text></g><g transform="translate(210.0919043059689 1900.1206990210958) rotate(0 57.125 26.5)"><path d="M0 0 C35.751818736735736 0, 71.50363747347147 0, 114.25 0 M0 0 C23.568781670089813 0, 47.137563340179625 0, 114.25 0 M114.25 0 C114.25 13.111394657567145, 114.25 26.22278931513429, 114.25 53 M114.25 0 C114.25 20.921167401596904, 114.25 41.84233480319381, 114.25 53 M114.25 53 C85.3933772421442 53, 56.536754484288394 53, 0 53 M114.25 53 C70.957347367052 53, 27.664694734103975 53, 0 53 M0 53 C0 40.39483490996063, 0 27.789669819921254, 0 0 M0 53 C0 38.70905513353645, 0 24.41811026707291, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(238.0919043059689 1915.1206990210958) rotate(0 29 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">infinite</text></g><g transform="translate(41.46471582028926 1777.6935835477643) rotate(0 328 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"># updating product: product without stock</text></g><g transform="translate(1940.5139130676002 2023.2022267517714) rotate(0 40 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">incoming</text></g><g transform="translate(2127.00322887767 2024.3310966546414) rotate(0 5.5 11.5)"><text x="5.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">0</text></g><g transform="translate(1940.5139130676002 2074.2022267517714) rotate(0 42 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">notify lost</text></g><g transform="translate(2127.00322887767 2081.3310966546414) rotate(0 5.5 11.5)"><text x="5.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">0</text></g><g transform="translate(1940.5139130676002 2138.2022267517714) rotate(0 53.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">after update</text></g><g transform="translate(2127.50322887767 2139.3310966546414) rotate(0 11 11.5)"><text x="11" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">15</text></g><g transform="translate(2093.0085709726354 2013.2666617032064) rotate(0 52.5 20.5)"><path d="M0 0 C29.524161050096158 0, 59.048322100192316 0, 105 0 M0 0 C36.504488250240684 0, 73.00897650048137 0, 105 0 M105 0 C105 10.325107226148248, 105 20.650214452296495, 105 41 M105 0 C105 9.495934232696891, 105 18.991868465393782, 105 41 M105 41 C74.71515481732786 41, 44.43030963465571 41, 0 41 M105 41 C82.80356870032847 41, 60.60713740065694 41, 0 41 M0 41 C0 29.32805828116834, 0 17.65611656233668, 0 0 M0 41 C0 30.19957923032343, 0 19.399158460646863, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2094.0085709726354 2070.2666617032064) rotate(0 51 22.5)"><path d="M0 0 C29.419563891738658 0, 58.839127783477316 0, 102 0 M0 0 C21.562247548252344 0, 43.12449509650469 0, 102 0 M102 0 C102 12.810667740181088, 102 25.621335480362177, 102 45 M102 0 C102 11.854120356962087, 102 23.708240713924173, 102 45 M102 45 C80.61069051995874 45, 59.22138103991747 45, 0 45 M102 45 C80.83884798511863 45, 59.67769597023725 45, 0 45 M0 45 C0 28.328645361587405, 0 11.65729072317481, 0 0 M0 45 C0 34.01418258436024, 0 23.028365168720484, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2315.630491090157 2215.0546687150145) rotate(0 21.5 11.5)"><text x="21.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">clear</text></g><g transform="translate(2398.813380718231 2204.477938912777) rotate(0 36 23)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.2929012427776867 4.6096996034750255, 2.8472593096168217 2.8216151898741626, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C0.8517481006590948 5.117188240914534, 1.964953025379638 3.836592464753179, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C4.09839555532937 7.479359926500602, 8.06364572979113 2.9178613990721978, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C3.417184224681352 8.263003919919068, 6.701223068495093 4.4851493859091285, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C4.626918667928739 12.968375982103431, 9.382148779051317 7.498109493201968, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C4.0565887613896 13.62446548827937, 8.241488965973039 8.81028850555384, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C5.715422844976365 17.813207512523, 11.164554928217507 11.544698117187984, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C5.3614574419609475 18.220398129401186, 10.456624122186673 12.35907935094436, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C7.255578161251454 22.13847384128991, 14.506322384829135 13.797446757645918, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C9.11980589185277 19.993925156140836, 18.23477784603177 9.50834938734777, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C9.516160549036586 25.634983627284917, 19.28894398446085 14.392682312560037, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C8.576053189518198 26.716453433070832, 17.408729265424075 16.555621924131874, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C7.888108409659516 33.60485572055613, 15.638237500777649 24.689352062249355, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C10.083295149170755 31.079582247471905, 20.028610979800128 19.638805116080903, 36.877284942009794 0.25662288638767805 M1.1886405524609494 47.40872423549325 C12.453225116675018 34.45030203235194, 23.717809680889086 21.491879829210635, 42.520359378862906 -0.13797931854138312 M1.1886405524609494 47.40872423549325 C17.347384032036103 28.820216236201507, 33.506127511611254 10.23170823690976, 42.520359378862906 -0.13797931854138312 M6.831714989314069 47.014122030564195 C21.55381318289163 30.078285380667076, 36.27591137646919 13.142448730769956, 47.50737478672552 0.22212805675232872 M6.831714989314069 47.014122030564195 C17.43780191320385 34.813214709081535, 28.043888837093625 22.61230738759887, 47.50737478672552 0.22212805675232872 M11.818730397176676 47.3742294058579 C21.766510546829146 35.93061739971741, 31.71429069648162 24.487005393576922, 53.15044922357863 -0.1724741481767289 M11.818730397176676 47.3742294058579 C25.628588071527656 31.48780542906593, 39.43844574587864 15.601381452273955, 53.15044922357863 -0.1724741481767289 M17.461804834029795 46.979627200928846 C31.670289547372953 30.63463527221622, 45.87877426071611 14.289643343503592, 58.13746463144125 0.1876332271169865 M17.461804834029795 46.979627200928846 C27.76486623666902 35.1273108656745, 38.06792763930825 23.274994530420155, 58.13746463144125 0.1876332271169865 M22.448820241892403 47.33973457622256 C34.76571105880082 33.170772505260544, 47.08260187570924 19.001810434298527, 63.78053906829436 -0.20696897781207468 M22.448820241892403 47.33973457622256 C35.18121105421159 32.69279443733952, 47.91360186653077 18.045854298456483, 63.78053906829436 -0.20696897781207468 M28.091894678745525 46.9451323712935 C38.55263945950966 34.91142205950037, 49.01338424027381 22.87771174770723, 68.76755447615697 0.1531383974816336 M28.091894678745525 46.9451323712935 C44.16297574114715 28.457468447218805, 60.23405680354878 9.969804523144113, 68.76755447615697 0.1531383974816336 M33.07891008660813 47.30523974658722 C43.00925016649015 35.8816902457304, 52.939590246372155 24.458140744873575, 73.09851085502908 1.2679553529981291 M33.07891008660813 47.30523974658722 C44.183068593544675 34.53136661143301, 55.28722710048122 21.757493476278793, 73.09851085502908 1.2679553529981291 M38.72198452346125 46.91063754165816 C50.32497873871401 33.56291956726326, 61.92797295396676 20.215201592868357, 73.49311305995813 6.911029789851241 M38.72198452346125 46.91063754165816 C50.67816756563262 33.15662229899264, 62.63435060780398 19.402607056327117, 73.49311305995813 6.911029789851241 M43.70899993132386 47.27074491695187 C52.82528990392236 36.783652941408874, 61.94157987652086 26.296560965865872, 73.23165623589668 13.30881380692713 M43.70899993132386 47.27074491695187 C51.6217935531243 38.168117121572735, 59.53458717492474 29.065489326193596, 73.23165623589668 13.30881380692713 M49.35207436817697 46.87614271202281 C56.227503305490856 38.9668664764438, 63.10293224280475 31.057590240864783, 72.97019941183524 19.706597824003016 M49.35207436817697 46.87614271202281 C58.04774158782605 36.87292186283115, 66.74340880747513 26.869701013639492, 72.97019941183524 19.706597824003016 M54.339089776039586 47.23625008731652 C58.367247243970056 42.602384996897925, 62.39540471190053 37.96851990647933, 73.3648016167643 25.34967226085613 M54.339089776039586 47.23625008731652 C59.4060130110888 41.40742167590182, 64.47293624613802 35.57859326448713, 73.3648016167643 25.34967226085613 M59.9821642128927 46.84164788238747 C62.6812477262444 43.736707480176584, 65.3803312395961 40.63176707796569, 73.10334479270284 31.747456277932027 M59.9821642128927 46.84164788238747 C63.23149924957844 43.10371551170787, 66.48083428626418 39.36578314102827, 73.10334479270284 31.747456277932027 M64.96917962075531 47.20175525768118 C67.55133689041521 44.23132311218837, 70.13349416007512 41.26089096669556, 73.49794699763191 37.39053071478514 M64.96917962075531 47.20175525768118 C67.69743126289549 44.06326076161429, 70.42568290503566 40.92476626554739, 73.49794699763191 37.39053071478514 M69.95619502861793 47.561862632974886 C70.67077826831753 46.739828649694815, 71.38536150801714 45.91779466641475, 73.23649017357046 43.78831473186103 M69.95619502861793 47.561862632974886 C71.17890829205336 46.15529192362867, 72.40162155548879 44.74872121428245, 73.23649017357046 43.78831473186103" stroke="#4c6ef5" stroke-width="0.5" fill="none"></path><path d="M0 0 C21.932444740086794 0, 43.86488948017359 0, 72 0 M0 0 C16.67752176448703 0, 33.35504352897406 0, 72 0 M72 0 C72 15.75052264314145, 72 31.5010452862829, 72 46 M72 0 C72 17.814064511843025, 72 35.62812902368605, 72 46 M72 46 C55.68650033399463 46, 39.37300066798925 46, 0 46 M72 46 C54.943963611871 46, 37.887927223742004 46, 0 46 M0 46 C0 35.37932818550617, 0 24.75865637101233, 0 0 M0 46 C0 32.96904833596199, 0 19.93809667192399, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2407.313380718231 2214.977938912777) rotate(0 25 11.5)"><text x="25" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">never</text></g><g transform="translate(2079.7394011263946 2209.0074728050386) rotate(0 71.39795918367349 18.459183673469397)"><path d="M-0.5332256704568863 0.6636613756418228 L142.39418197377609 -0.21745406091213226 L142.0709440778105 37.68443713169921 L-1.0454198271036148 37.45789322834838" stroke="none" stroke-width="0" fill="#fff"></path><path d="M1.2337845712900162 0.015040740370750427 C28.56659816368199 -0.6406339541427333, 60.50770338205053 0.5121108159073156, 142.37637738092826 0.3370445817708969 M0.969361238181591 0.0363282635807991 C53.000192554431926 -1.0081881181698065, 105.90986145613148 -1.295944322774909, 143.62886483921693 -0.8408563658595085 M144.35668972834037 -0.005633488297462463 C143.05124262072758 7.868321860368756, 144.06162193515019 15.354444567433411, 143.8131206403582 38.28928787093986 M142.8561464096515 -0.7321699187159538 C142.48485237584282 9.912379578227283, 143.74567300305534 21.5151276225338, 141.94549305691407 36.03820743989576 M143.7820804487078 35.948196714934 C103.69038879167367 34.684089546974484, 62.7665590731161 37.91535604554016, 0.4336971193552017 35.91201574188102 M143.5466149593799 37.79356136750806 C111.85944364060252 36.627684100235264, 80.07601225102437 37.33753226574735, -0.7850254252552986 36.95606484841932 M1.762398138642311 37.63891774993766 C1.6323946739687605 28.70091673362313, -1.345415708874257 16.862387763207035, 0.34800995886325836 -1.2112757116556168 M0.9106399342417717 36.41863313150037 C-0.325401134167095 27.893693413798267, -0.25188214269675807 20.403612399709445, -0.8587933257222176 -0.8126259371638298" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2114.387360310068 2215.4666564785084) rotate(0 5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(2144.887360310068 2214.9666564785084) rotate(0 5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(2233.887360310068 2207.9666564785084) rotate(0 17.75 17.75)"><path d="M-0.21745406091213226 -0.7249742895364761 L36.266069784760475 -1.0454198271036148 L36.039525881409645 34.953821524977684 L-0.5811678022146225 33.94901929795742" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-1.6772920042276382 -0.5623360723257065 C12.31542037986219 -0.07014615889638665, 26.016979809850454 1.8284014904871584, 36.63062797486782 0.5429748445749283 M-0.6205151602625847 -0.8873010352253914 C13.182961030676962 0.9743744572624564, 27.34160842522979 -0.8362084189429879, 36.01312632113695 -0.8793523982167244 M35.90208564698696 1.0762657076120377 C35.920972196497026 14.437571438774468, 36.869920579828324 26.54535238966346, 36.92520032823086 35.345044031739235 M34.882127709686756 0.6866742894053459 C35.69470356430858 10.01338423974812, 34.359919771812855 21.528746228665113, 35.70761031657457 35.05759137123823 M33.8974636644125 35.468544855713844 C24.72829246856272 36.09227961298078, 9.692773006111384 34.0602547525987, -0.8783871084451675 34.875888243317604 M35.65491981059313 35.63417714089155 C23.049795074388385 34.88912582490593, 8.907751698046923 35.3702452192083, 0.15197987109422684 35.72035758942366 M1.736088141798973 34.21069277822971 C-0.2767997700348496 22.069753262773155, -1.3391734081879259 6.453609279543162, -1.8685132414102554 0.9973238855600357 M-0.6993556544184685 34.90320556610823 C0.31328725669533014 20.75843490771949, -0.6352202906832098 7.467843631654976, 0.3318306878209114 -0.20086819678544998" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2234.887360310068 2208.9666564785084) rotate(0 17.5 4.5)"><path d="M-0.7249742895364761 0.7660697847604752 L33.954580172896385 0.5395258814096451 L34.453821524977684 8.418832197785378 L-1.5509807020425797 9.610531702637672" stroke="none" stroke-width="0" fill="#000"></path><path d="M-0.5623360723257065 -0.5245472341775894 C10.10678030923009 0.6305706825107336, 22.531649254262447 1.4241540756076574, 35.54297484457493 1.938722476363182 M-0.8873010352253914 -0.9082713648676872 C11.460095394402742 -0.6236760597676039, 20.276661440730095 0.7303066272288561, 34.120647601783276 0.7803856804966927 M35.48431956842542 0.18988746330142015 C35.46070591054857 3.314379166066647, 34.870041213855146 6.03627000823617, 34.93026981428265 9.054205238074065 M35.30900343023241 0.20458074845373636 C34.56563543990254 1.6449751149863008, 34.85883403733373 4.175518788769842, 34.800916117057206 9.221886468306185 M34.968544855713844 10.628730162978172 C26.631495725363493 7.713204536214471, 15.797269470989704 7.84116903282702, -0.6241117566823959 10.501393184065819 M35.13417714089155 9.864767976105213 C20.651795502752066 9.091919435188174, 7.569735825061798 9.206201804801822, 0.22035758942365646 9.881199069321156 M-0.580188249796629 8.932994066923857 C0.0806218392401934 5.4306782484054565, -0.7464274399727583 2.1106736786663536, 0.4487957485020161 0.8195759408175946 M-0.26855749525129796 9.06114672459662 C-0.326128788292408 6.384079122170806, -0.05964756757020948 4.6488453973084685, -0.0903906885534525 -0.04892716370522976" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2242.387360310068 2200.4666564785084) rotate(0 3 7)"><path d="M0.7660697847604752 -1.0454198271036148 L6.539525881409645 -0.546178475022316 L5.4188321977853775 12.44901929795742 L0.6105317026376724 12.975818023085594" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-0.1573641702532768 -0.1258622959256172 C1.3105869054794312 0.4605720810592175, 2.7581354543566703 0.1797625355422497, 6.581616742908954 0.021796958148479484 M-0.27248140946030613 0.24988394156098365 C1.308709875494242 -0.24005285918712616, 3.2758714668452744 -0.2105676573514938, 6.234115704149008 -0.0008450232446193806 M6.295380498468876 0.712041591107845 C6.987790362089871 4.039350315928459, 7.0257862250506875 8.383771772682667, 6.084319259226322 12.974962113797664 M6.318236719816923 -0.5952977173030376 C5.297385944426059 3.2569841168820863, 6.058825100958347 6.482704214006663, 6.345156728476286 13.660440278798342 M6.488619048893452 14.13010913580656 C3.6300677686929705 13.51955802336335, 1.6004303678870209 13.811822818666696, 0.4504179552197457 14.525116412341594 M6.259430392831564 13.76449237242341 C3.9169691093266006 13.916878819167614, 1.856913679093122 14.07415790528059, 0.2643597207963467 14.108082560449839 M-0.10423145145177837 14.243606971204281 C-0.9694191680848598 7.575133657455444, -1.4294854389131069 3.9342222943902008, 1.2748959079384803 -0.6996279016137122 M0.09511712715029719 13.398844671994448 C-0.4709283643960952 10.551809810847045, 0.3301912730932236 7.336269853264093, -0.07610892131924629 -0.2537410013377666" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2257.387360310068 2200.4666564785084) rotate(0 3 7)"><path d="M-1.0454198271036148 0.5395258814096451 L5.453821524977684 -0.5811678022146225 L4.44901929795742 14.610531702637672 L-1.0241819769144058 15.71179236471653" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-0.1258622959256172 0.10111337453126912 C1.7405143976211548 0.35492480948567384, 2.7565172508358957 0.5973531599342823, 6.02179695814848 -0.23903321474790573 M0.24988394156098365 -0.25225690975785253 C1.1343999825417996 0.20843417823314664, 2.591576088219881 0.288611986041069, 5.9991549767553805 0.009882958978414513 M6.712041591107845 0.9596443668007848 C5.8685684402287 5.4791001826524734, 5.966869421750307 9.047239165008069, 4.974962113797664 13.19619512706995 M5.404702282696962 -0.6161119349300861 C5.9569233903288845 3.4803060151636602, 5.786448360383511 7.015114315599203, 5.660440278798342 14.312697874754667 M6.130109135806561 13.698094518482685 C4.201262578368187 13.785345772355795, 3.1742882743477816 14.49927986010909, 0.5251164123415947 14.294340141117573 M5.76449237242341 14.011309250444175 C4.015876304358243 14.097480039894581, 2.2802035041153426 14.316245799362658, 0.10808256044983866 14.25327547416091 M0.24360697120428076 13.152107001841069 C-0.9526626242697239 7.276779031753539, 0.7883782254159449 4.444372509419917, -0.6996279016137122 -0.9384387955069542 M-0.6011553280055523 13.431161843985318 C-0.10307776391506192 11.011379397660493, -0.05705651700496668 7.482086911052464, -0.2537410013377666 0.26812442466616626" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(2250.887360310068 2216.9666564785084) rotate(0 0.20799543491568784 12.861703209578991)"><path d="M0.3370445817708969 1.4790066629648209 C1.1970670645311474 7.748928401209415, 2.141103164218366 14.483514787964525, -0.2967773824930191 25.25896967947483 M-0.8408563658595085 -0.9776364043354988 C0.3780693576857448 4.715135126076639, 0.7509636652842164 11.190323036797345, 0.5329431965947151 26.70104282349348" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(2241.387360310068 2215.9666564785084) rotate(0 0.250685129314661 14.525629587471485)"><path d="M1.4790066629648209 1.1306279748678207 C0.6211254256218672 9.60351373706013, 0.28769342735409736 14.533647750355303, -0.7410303205251694 26.225397929549217 M-0.9776364043354988 0.5131263211369514 C-0.5415409543365239 6.641430140696466, 0.43958113148808486 11.750827835164964, 0.7010428234934807 28.53813285380602" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(2260.887360310068 2217.4666564785084) rotate(0 0.881765391677618 12.415816836059093)"><path d="M1.1306279748678207 0.5429748445749283 C2.400230086557567 7.176649219505489, 0.08326465371996172 12.978047614134848, -0.2746020704507828 23.683457270264626 M0.5131263211369514 -0.8793523982167244 C1.14090927798301 9.785861305184664, 0.9684087648615243 19.763734376095236, 2.038132853806019 25.71098607033491" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(2269.887360310068 2225.4666564785084) rotate(0 -17.636783942580223 0.7824612371146031)"><path d="M0.5429748445749283 1.938722476363182 C-10.700319261848927 -0.6045706267654896, -22.78698189854622 -1.5823953147232532, -35.816542729735374 1.665892943739891 M-0.8793523982167244 0.7803856804966927 C-7.343905100226403 0.20740614578127864, -14.481133888661862 0.7125958029925823, -33.78901392966509 0.5086011365056038" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(2269.387360310068 2234.4666564785084) rotate(0 -16.776338193565607 0.44000930051925025)"><path d="M1.938722476363182 0.0726565271615982 C-14.25333623595536 -0.7693445153534413, -28.6933729172498 -0.9709065914154053, -34.33410705626011 -0.681712731719017 M0.7803856804966927 -0.0028167441487312317 C-7.24243448458612 0.08671231970191007, -14.01775377176702 0.2988919261097909, -35.491398863494396 1.6854602620005608" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(1017.5202442733594 258.5144794614512) rotate(0 54 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">next restock</text></g><g transform="translate(1197.5202442733594 263.5144794614512) rotate(0 40 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">unknown</text></g><g transform="translate(1150.5202442733594 252.01447946145117) rotate(0 94.5 23)"><path d="M0 0 C70.95094501152634 0, 141.9018900230527 0, 189 0 M0 0 C63.35328986272216 0, 126.70657972544431 0, 189 0 M189 0 C189 13.924661253392697, 189 27.849322506785395, 189 46 M189 0 C189 12.685054327547553, 189 25.370108655095105, 189 46 M189 46 C127.70845397338272 46, 66.41690794676542 46, 0 46 M189 46 C122.6631328381598 46, 56.32626567631959 46, 0 46 M0 46 C0 27.616077138483522, 0 9.232154276967044, 0 0 M0 46 C0 29.85423505157232, 0 13.708470103144641, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1493.9141836672989 256.7974508453981) rotate(0 42.85000000000002 19.5)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.832670802688257 3.9887657545743176, 3.9267984294379623 1.5797474920727463, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C0.9784212350667891 4.971467469048262, 2.2182992941950266 3.545150921020635, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C3.37460858018232 8.311981596267827, 6.6160717794970285 4.5831047386066475, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C3.1916574118686847 8.522442840360005, 6.250169442869758 5.004027226791005, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C3.473213240430706 14.295562257136579, 7.074737924055251 10.152482043268261, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C4.64777413008577 12.94438451731999, 9.423859703365379 7.450126563635084, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C5.737950658843504 17.787292227166486, 11.209610555951786 11.492867546474958, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C5.81762107869453 17.695641893179832, 11.368951395653838 11.30956687850165, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C8.842980156026423 20.312376736941175, 17.681126374379073 10.145252548948452, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C10.475407666861928 18.43448370139758, 20.945981396050083 6.389466477861255, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C9.226002889761762 25.968771831627873, 18.708628665911203 15.060258721245951, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C9.014899617064208 26.211618367200103, 18.286422120516093 15.545951792390408, 31.89026953414718 -0.10348448890603734 M2.1061564055129054 40.256230638194594 C14.395472293624229 26.118989894152126, 26.684788181735552 11.981749150109657, 36.877284942009794 0.25662288638767805 M2.1061564055129054 40.256230638194594 C15.87821753425575 24.413286613372307, 29.650278662998595 8.570342588550023, 36.877284942009794 0.25662288638767805 M7.093171813375516 40.6163380134883 C20.763277283758065 24.89068055698112, 34.43338275414061 9.165023100473938, 42.520359378862906 -0.13797931854138312 M7.093171813375516 40.6163380134883 C20.995815386415636 24.62317607020873, 34.89845895945576 8.630014126929158, 42.520359378862906 -0.13797931854138312 M12.736246250228632 40.221735808559245 C26.521045039779274 24.364138781161774, 40.305843829329916 8.506541753764303, 47.50737478672552 0.22212805675232872 M12.736246250228632 40.221735808559245 C22.469745334088707 29.02462597077197, 32.20324441794878 17.827516132984698, 47.50737478672552 0.22212805675232872 M17.723261658091243 40.58184318385296 C31.71044703869748 24.49142701605997, 45.69763241930372 8.401010848266978, 53.15044922357863 -0.1724741481767289 M17.723261658091243 40.58184318385296 C28.99194369025733 27.618707383030046, 40.26062572242342 14.65557158220713, 53.15044922357863 -0.1724741481767289 M22.710277065953854 40.941950559146676 C32.31425868693094 29.893833518843415, 41.918240307908036 18.84571647854015, 58.13746463144125 0.1876332271169865 M22.710277065953854 40.941950559146676 C35.053310785473414 26.742914518947746, 47.396344504992975 12.543878478748816, 58.13746463144125 0.1876332271169865 M28.353351502806966 40.54734835421761 C37.94887564361349 29.508960531907263, 47.54439978442001 18.47057270959692, 63.78053906829436 -0.20696897781207468 M28.353351502806966 40.54734835421761 C39.671166823849696 27.52769117012815, 50.988982144892425 14.508033986038686, 63.78053906829436 -0.20696897781207468 M33.34036691066958 40.90745572951133 C42.910973032649395 29.897732808829765, 52.4815791546292 18.888009888148204, 68.76755447615697 0.1531383974816336 M33.34036691066958 40.90745572951133 C40.845781098123865 32.273464365155576, 48.35119528557814 23.639473000799825, 68.76755447615697 0.1531383974816336 M38.98344134752269 40.51285352458227 C47.85792328245242 30.303929876185542, 56.73240521738214 20.09500622778881, 74.41062891301009 -0.2414638074474169 M38.98344134752269 40.51285352458227 C51.850272077486025 25.711257951772012, 64.71710280744935 10.909662378961755, 74.41062891301009 -0.2414638074474169 M43.97045675538531 40.872960899875984 C57.216362961433376 25.635288875425577, 70.46226916748145 10.397616850975169, 79.3976443208727 0.11864356784629138 M43.97045675538531 40.872960899875984 C57.89790854275577 24.85126037059122, 71.82536033012623 8.829559841306455, 79.3976443208727 0.11864356784629138 M49.613531192238426 40.47835869494692 C58.74595402494579 29.972707986816566, 67.87837685765317 19.46705727868621, 85.04071875772581 -0.27595863708276624 M49.613531192238426 40.47835869494692 C61.246167829479475 27.096541014783178, 72.87880446672051 13.714723334619432, 85.04071875772581 -0.27595863708276624 M54.60054660010103 40.838466070240635 C62.96835188884398 31.212407228293863, 71.33615717758694 21.586348386347094, 88.0595570786169 2.348277478879261 M54.60054660010103 40.838466070240635 C65.56105143686412 28.229847578835304, 76.52155627362723 15.62122908742997, 88.0595570786169 2.348277478879261 M60.24362103695415 40.44386386531157 C68.82577589031709 30.571224056124393, 77.40793074368003 20.698584246937216, 88.45415928354596 7.991351915732373 M60.24362103695415 40.44386386531157 C66.07067846212402 33.74060109633355, 71.89773588729389 27.037338327355528, 88.45415928354596 7.991351915732373 M65.23063644481675 40.80397124060529 C71.06352488858407 34.09400065205085, 76.89641333235139 27.384030063496404, 88.19270245948451 14.389135932808273 M65.23063644481675 40.80397124060529 C73.56723629186938 31.213810152912455, 81.903836138922 21.623649065219617, 88.19270245948451 14.389135932808273 M70.87371088166988 40.40936903567623 C75.80055067590764 34.74168818894585, 80.7273904701454 29.074007342215474, 87.93124563542307 20.786919949884158 M70.87371088166988 40.40936903567623 C76.02338835294613 34.485342765342246, 81.17306582422239 28.56131649500827, 87.93124563542307 20.786919949884158 M75.8607262895325 40.76947641096994 C78.70849720079879 37.49349072364621, 81.55626811206508 34.217505036322486, 88.32584784035213 26.429994386737274 M75.8607262895325 40.76947641096994 C80.34716357299014 35.60842069910181, 84.83360085644779 30.44736498723369, 88.32584784035213 26.429994386737274 M81.5038007263856 40.374874206040886 C84.11595924225449 37.369929574732005, 86.72811775812337 34.36498494342312, 88.06439101629068 32.82777840381317 M81.5038007263856 40.374874206040886 C83.01921927251676 38.6315845868548, 84.53463781864794 36.88829496766872, 88.06439101629068 32.82777840381317" stroke="#fa5252" stroke-width="0.5" fill="none"></path><path d="M0 0 C27.48174813024704 0, 54.96349626049408 0, 85.70000000000013 0 M0 0 C23.505595291927495 0, 47.01119058385499 0, 85.70000000000013 0 M85.70000000000013 0 C85.70000000000013 11.344363928586246, 85.70000000000013 22.68872785717249, 85.70000000000013 39 M85.70000000000013 0 C85.70000000000013 10.094785391539336, 85.70000000000013 20.189570783078672, 85.70000000000013 39 M85.70000000000013 39 C51.926018922403536 39, 18.15203784480694 39, 0 39 M85.70000000000013 39 C56.20642761819073 39, 26.71285523638133 39, 0 39 M0 39 C0 27.112638091295956, 0 15.225276182591912, 0 0 M0 39 C0 29.743110812455413, 0 20.48622162491083, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1508.0141836672988 264.59745084539827) rotate(0 25 11.5)"><text x="25" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">never</text></g><g transform="translate(1031.2702442733594 1351.859549495717) rotate(0 54 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">next restock</text></g><g transform="translate(1211.2702442733594 1356.859549495717) rotate(0 25 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">never</text></g><g transform="translate(1164.2702442733594 1345.359549495717) rotate(0 94.5 23)"><path d="M0 0 C43.93486205711961 0, 87.86972411423922 0, 189 0 M0 0 C68.47068202123046 0, 136.94136404246092 0, 189 0 M189 0 C189 11.259486769139768, 189 22.518973538279536, 189 46 M189 0 C189 17.517849661409855, 189 35.03569932281971, 189 46 M189 46 C146.6980354629457 46, 104.3960709258914 46, 0 46 M189 46 C115.34704683199524 46, 41.694093663990486 46, 0 46 M0 46 C0 35.74880533367396, 0 25.497610667347907, 0 0 M0 46 C0 28.277714131772516, 0 10.555428263545032, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1429.4141836672989 1356.1425208796638) rotate(0 21.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">clear</text></g><g transform="translate(1507.6641836672989 1350.1425208796638) rotate(0 42.85000000000002 19.5)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.1680636657135124 4.75330880816367, 2.597584155488473 3.1088335992514513, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.3595743526068416 4.53300096431639, 2.9806055292751314 2.6682179115568903, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C2.4478070758704646 9.378144766593092, 4.762468770873318 6.7154310792571765, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C2.3163147367899652 9.52940939926289, 4.499484092712319 7.017960344596775, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C6.023305356175783 11.36201685168006, 12.174922155545405 4.285391232355222, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C5.75875087257915 11.666351971598296, 11.64581318835214 4.894061472191693, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C6.375578048976325 17.053785821978902, 12.484865336217428 10.025854736099792, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C6.41004029965436 17.01414153755716, 12.553789837573499 9.946566167256305, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C6.827577750615223 22.630831991963447, 13.650321563556673 14.782163058992994, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C7.413960704011991 21.95627556784286, 14.82308747035021 13.433050210751812, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C10.72703285783447 24.24203437806507, 21.710688602056617 11.606783814120345, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C6.754050063429236 28.812428267181495, 13.76472301324615 20.747571592353193, 31.89026953414718 -0.10348448890603734 M2.1061564055129054 40.256230638194594 C14.642324438868245 25.835018985008674, 27.178492472223585 11.413807331822756, 36.877284942009794 0.25662288638767805 M2.1061564055129054 40.256230638194594 C11.04377932938536 29.974671590917456, 19.981402253257816 19.693112543640318, 36.877284942009794 0.25662288638767805 M7.093171813375516 40.6163380134883 C21.14128179646881 24.455836107771706, 35.1893917795621 8.295334202055109, 42.520359378862906 -0.13797931854138312 M7.093171813375516 40.6163380134883 C19.96728173679834 25.806368686492192, 32.84139166022117 10.996399359496078, 42.520359378862906 -0.13797931854138312 M12.736246250228632 40.221735808559245 C21.78015876421793 29.81790457479522, 30.824071278207228 19.414073341031195, 47.50737478672552 0.22212805675232872 M12.736246250228632 40.221735808559245 C20.85053294298741 30.887316750075698, 28.96481963574619 21.552897691592147, 47.50737478672552 0.22212805675232872 M17.723261658091243 40.58184318385296 C30.729227301916936 25.62019120179402, 43.73519294574263 10.658539219735083, 53.15044922357863 -0.1724741481767289 M17.723261658091243 40.58184318385296 C25.523898748441372 31.60823671891775, 33.324535838791505 22.63463025398254, 53.15044922357863 -0.1724741481767289 M22.710277065953854 40.941950559146676 C30.290159765407076 32.22229297125459, 37.8700424648603 23.5026353833625, 58.13746463144125 0.1876332271169865 M22.710277065953854 40.941950559146676 C31.891231849548355 30.38047022797496, 41.072186633142856 19.81898989680325, 58.13746463144125 0.1876332271169865 M28.353351502806966 40.54734835421761 C37.29675856475941 30.259135417230254, 46.24016562671184 19.970922480242898, 63.78053906829436 -0.20696897781207468 M28.353351502806966 40.54734835421761 C42.26060010749494 24.548888928016098, 56.167848712182916 8.550429501814584, 63.78053906829436 -0.20696897781207468 M33.34036691066958 40.90745572951133 C46.267118746162495 26.036928809974075, 59.19387058165542 11.166401890436823, 68.76755447615697 0.1531383974816336 M33.34036691066958 40.90745572951133 C43.78269662308831 28.894929530559565, 54.225026335507046 16.882403331607804, 68.76755447615697 0.1531383974816336 M38.98344134752269 40.51285352458227 C50.99459514721693 26.69560165914144, 63.00574894691116 12.878349793700604, 74.41062891301009 -0.2414638074474169 M38.98344134752269 40.51285352458227 C53.051938699783015 24.32889863346957, 67.12043605204335 8.144943742356872, 74.41062891301009 -0.2414638074474169 M43.97045675538531 40.872960899875984 C56.12724425861781 26.888176622858133, 68.28403176185031 12.903392345840285, 79.3976443208727 0.11864356784629138 M43.97045675538531 40.872960899875984 C51.517456439565606 32.19113089388803, 59.064456123745906 23.509300887900075, 79.3976443208727 0.11864356784629138 M49.613531192238426 40.47835869494692 C56.73158547110044 32.28997393165974, 63.84963974996244 24.101589168372556, 85.04071875772581 -0.27595863708276624 M49.613531192238426 40.47835869494692 C58.92890103844186 29.762251522295255, 68.24427088464529 19.04614434964359, 85.04071875772581 -0.27595863708276624 M54.60054660010103 40.838466070240635 C63.51834177647235 30.579716237275164, 72.43613695284365 20.320966404309697, 88.0595570786169 2.348277478879261 M54.60054660010103 40.838466070240635 C67.96149522775357 25.468452878486247, 81.32244385540612 10.098439686731854, 88.0595570786169 2.348277478879261 M60.24362103695415 40.44386386531157 C68.69597646440566 30.72054121496833, 77.14833189185715 20.997218564625086, 88.45415928354596 7.991351915732373 M60.24362103695415 40.44386386531157 C69.59998204984933 29.68060174952259, 78.95634306274451 18.91733963373361, 88.45415928354596 7.991351915732373 M65.23063644481675 40.80397124060529 C73.04455754813084 31.815083266835224, 80.85847865144494 22.826195293065158, 88.19270245948451 14.389135932808273 M65.23063644481675 40.80397124060529 C73.3015613409806 31.519434223004897, 81.37248623714444 22.2348972054045, 88.19270245948451 14.389135932808273 M70.87371088166988 40.40936903567623 C77.42636322445753 32.87140479703058, 83.97901556724518 25.33344055838493, 87.93124563542307 20.786919949884158 M70.87371088166988 40.40936903567623 C75.26372668564532 35.359233547581944, 79.65374248962075 30.30909805948766, 87.93124563542307 20.786919949884158 M75.8607262895325 40.76947641096994 C79.06707914381792 37.080989384997075, 82.27343199810335 33.392502359024206, 88.32584784035213 26.429994386737274 M75.8607262895325 40.76947641096994 C79.34946265055413 36.75614432012746, 82.83819901157577 32.74281222928498, 88.32584784035213 26.429994386737274 M81.5038007263856 40.374874206040886 C83.41321672213974 38.17834236828289, 85.32263271789387 35.98181053052489, 88.06439101629068 32.82777840381317 M81.5038007263856 40.374874206040886 C82.85958293045782 38.815225191403755, 84.21536513453002 37.25557617676662, 88.06439101629068 32.82777840381317" stroke="#fa5252" stroke-width="0.5" fill="none"></path><path d="M0 0 C31.05126833669846 0, 62.10253667339692 0, 85.70000000000013 0 M0 0 C25.29206354983155 0, 50.5841270996631 0, 85.70000000000013 0 M85.70000000000013 0 C85.70000000000013 7.99688525274396, 85.70000000000013 15.99377050548792, 85.70000000000013 39 M85.70000000000013 0 C85.70000000000013 14.824664580076934, 85.70000000000013 29.64932916015387, 85.70000000000013 39 M85.70000000000013 39 C54.724368588999 39, 23.74873717799786 39, 0 39 M85.70000000000013 39 C67.95390589348982 39, 50.20781178697951 39, 0 39 M0 39 C0 26.822433661669493, 0 14.644867323338985, 0 0 M0 39 C0 24.301500666886568, 0 9.603001333773136, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1521.7641836672988 1357.942520879664) rotate(0 25 11.5)"><text x="25" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">never</text></g><g transform="translate(916.5709458336519 1853.4558419016075) rotate(0 412 251.56944444444457)"><path d="M0 0 C237.1811243116856 0, 474.3622486233712 0, 824 0 M0 0 C172.54678277373316 0, 345.0935655474663 0, 824 0 M824 0 C824 112.20485208479487, 824 224.40970416958973, 824 503.13888888888914 M824 0 C824 119.43370529266288, 824 238.86741058532576, 824 503.13888888888914 M824 503.13888888888914 C570.5043474137783 503.13888888888914, 317.0086948275566 503.13888888888914, 0 503.13888888888914 M824 503.13888888888914 C513.3626734793186 503.13888888888914, 202.72534695863715 503.13888888888914, 0 503.13888888888914 M0 503.13888888888914 C0 365.26225807884106, 0 227.38562726879297, 0 0 M0 503.13888888888914 C0 376.0602100148592, 0 248.98153114082922, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1009.5709458336516 1923.4558419016075) rotate(0 25 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Stock</text></g><g transform="translate(1046.9876125003182 2113.8566355524) rotate(0 81 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">current stock is 15</text></g><g transform="translate(995.3934566561632 2229.455278815496) rotate(0 288.4999999999999 28.5)"><path d="M0 0 C115.43863970711827 0, 230.87727941423654 0, 576.9999999999999 0 M0 0 C117.08345114514229 0, 234.16690229028458 0, 576.9999999999999 0 M576.9999999999999 0 C576.9999999999999 15.664222944527864, 576.9999999999999 31.32844588905573, 576.9999999999999 57 M576.9999999999999 0 C576.9999999999999 11.606445883959532, 576.9999999999999 23.212891767919064, 576.9999999999999 57 M576.9999999999999 57 C453.28450038954605 57, 329.5690007790922 57, 0 57 M576.9999999999999 57 C367.806977636367 57, 158.61395527273407 57, 0 57 M0 57 C0 45.09641448184848, 0 33.192828963696954, 0 0 M0 57 C0 39.794306612759826, 0 22.58861322551965, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1490.393456656163 2229.455278815496) rotate(0 41 29)"><path d="M0 0 C19.06852476447821 0, 38.13704952895642 0, 82 0 M0 0 C19.28069086223841 0, 38.56138172447682 0, 82 0 M82 0 C82 23.10410188883543, 82 46.20820377767086, 82 58 M82 0 C82 13.37995346337557, 82 26.75990692675114, 82 58 M82 58 C60.44384906440973 58, 38.887698128819466 58, 0 58 M82 58 C49.94147968143225 58, 17.882959362864497 58, 0 58 M0 58 C0 42.55719810277223, 0 27.11439620554447, 0 0 M0 58 C0 45.967039696872234, 0 33.93407939374447, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(1529.393456656163 2241.455278815496) rotate(0 0 17)"><path d="M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34 M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1529.393456656163 2241.455278815496) rotate(0 0 17)"><path d="M-5.814342436536368 18.025225446639556 C-4.172222794085663 22.536912084315766, -2.5301031516349584 27.04859872199198, 0 34 M-5.814342436536368 18.025225446639556 C-3.6142086520908348 24.070043339182902, -1.4140748676453017 30.11486123172625, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1529.393456656163 2241.455278815496) rotate(0 0 17)"><path d="M5.814342436536368 18.025225446639556 C4.172222794085663 22.536912084315766, 2.5301031516349584 27.04859872199198, 0 34 M5.814342436536368 18.025225446639556 C3.6142086520908348 24.070043339182902, 1.4140748676453017 30.11486123172625, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(1026.3793720786027 2245.455278815496) rotate(0 35.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">address</text></g><g transform="translate(922.2888234866489 1782.589056174199) rotate(0 244 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"># updating product: initial state</text></g><g transform="translate(1046.4061697165266 2180.939090707132) rotate(0 54 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">next restock</text></g><g transform="translate(1401.120455430812 2172.1533764214173) rotate(0 36 23)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.0909203447289906 4.842052047452373, 2.4432975135194295 3.2863200778288584, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C0.9609887858427564 4.991521207896073, 2.183434395746961 3.585258398716258, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C4.055934280738017 7.528206035320831, 7.978723180608424 3.015553616712655, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C2.954120567050224 8.795697722190123, 5.775095753232837 5.5505369904512385, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C3.931789477079368 13.76803064219365, 7.9918903973525754 9.097418813382406, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C3.3020586491481456 14.49245309169886, 6.73242874149013 10.546263712392824, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C8.176788733731076 14.981729955488115, 16.08728670572693 5.881743003118217, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C4.890129338938814 18.76259908855326, 9.513967916142406 13.443481269248503, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C5.323469502644222 24.361110601469832, 10.64210506761467 18.242720278005763, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C7.166012140537533 22.241507761879706, 14.327190343401293 14.003514598825511, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C9.004653777300126 26.22340485757015, 18.26593044098793 15.569524773130503, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C11.149446486180546 23.756103085236145, 22.55551585874877 10.634921228462495, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C12.671130608757073 28.10261809167754, 25.204281898972763 13.68487680449218, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C13.073179670552559 27.640113552835167, 26.008380022563735 12.759867726807432, 36.877284942009794 0.25662288638767805 M1.1886405524609494 47.40872423549325 C13.602967845916378 33.127674320200626, 26.017295139371807 18.846624404907992, 42.520359378862906 -0.13797931854138312 M1.1886405524609494 47.40872423549325 C17.00985498266705 29.208498991115004, 32.83106941287315 11.008273746736755, 42.520359378862906 -0.13797931854138312 M6.831714989314069 47.014122030564195 C15.36440546127615 37.19838448302329, 23.89709593323823 27.382646935482388, 47.50737478672552 0.22212805675232872 M6.831714989314069 47.014122030564195 C19.931300316280954 31.94477292272559, 33.030885643247835 16.87542381488699, 47.50737478672552 0.22212805675232872 M11.818730397176676 47.3742294058579 C23.96493341124092 33.40162119078579, 36.11113642530516 19.429012975713682, 53.15044922357863 -0.1724741481767289 M11.818730397176676 47.3742294058579 C25.335211234181067 31.82529687415986, 38.85169207118546 16.276364342461818, 53.15044922357863 -0.1724741481767289 M17.461804834029795 46.979627200928846 C26.923227680139938 36.095505271404654, 36.38465052625008 25.211383341880463, 58.13746463144125 0.1876332271169865 M17.461804834029795 46.979627200928846 C32.18211722848127 30.045844877928026, 46.902429622932736 13.112062554927206, 58.13746463144125 0.1876332271169865 M22.448820241892403 47.33973457622256 C32.21982389418312 36.09948066778622, 41.99082754647384 24.859226759349877, 63.78053906829436 -0.20696897781207468 M22.448820241892403 47.33973457622256 C35.79387852241059 31.98800113779131, 49.13893680292877 16.63626769936006, 63.78053906829436 -0.20696897781207468 M28.091894678745525 46.9451323712935 C41.15523817334838 31.917474722426277, 54.21858166795123 16.889817073559055, 68.76755447615697 0.1531383974816336 M28.091894678745525 46.9451323712935 C42.866012590319265 29.94945388126103, 57.640130501893 12.953775391228561, 68.76755447615697 0.1531383974816336 M33.07891008660813 47.30523974658722 C48.41568418493783 29.66229935518325, 63.75245828326753 12.019358963779283, 73.09851085502908 1.2679553529981291 M33.07891008660813 47.30523974658722 C41.81100230326506 37.26011673160461, 50.54309451992199 27.214993716622008, 73.09851085502908 1.2679553529981291 M38.72198452346125 46.91063754165816 C48.26506034763322 35.93258460581613, 57.80813617180518 24.954531669974106, 73.49311305995813 6.911029789851241 M38.72198452346125 46.91063754165816 C50.20061821505383 33.70597998478739, 61.67925190664641 20.501322427916612, 73.49311305995813 6.911029789851241 M43.70899993132386 47.27074491695187 C51.89049263716788 37.859014184239776, 60.0719853430119 28.447283451527678, 73.23165623589668 13.30881380692713 M43.70899993132386 47.27074491695187 C54.73073308969366 34.591691298743015, 65.75246624806346 21.912637680534164, 73.23165623589668 13.30881380692713 M49.35207436817697 46.87614271202281 C58.30371628344327 36.57845665994509, 67.25535819870957 26.280770607867368, 72.97019941183524 19.706597824003016 M49.35207436817697 46.87614271202281 C58.308125954591326 36.57338391357013, 67.26417754100568 26.270625115117458, 72.97019941183524 19.706597824003016 M54.339089776039586 47.23625008731652 C60.96690458165455 39.61182132602541, 67.59471938726952 31.98739256473429, 73.3648016167643 25.34967226085613 M54.339089776039586 47.23625008731652 C59.307395360843515 41.52086830513838, 64.27570094564744 35.80548652296024, 73.3648016167643 25.34967226085613 M59.9821642128927 46.84164788238747 C62.722751713026106 43.68896260500919, 65.46333921315951 40.53627732763091, 73.10334479270284 31.747456277932027 M59.9821642128927 46.84164788238747 C64.43769243441663 41.71614897886472, 68.89322065594057 36.59065007534198, 73.10334479270284 31.747456277932027 M64.96917962075531 47.20175525768118 C67.65326893737495 44.11406370568252, 70.3373582539946 41.02637215368385, 73.49794699763191 37.39053071478514 M64.96917962075531 47.20175525768118 C67.24603681104708 44.58253067821555, 69.52289400133883 41.96330609874992, 73.49794699763191 37.39053071478514 M69.95619502861793 47.561862632974886 C70.69600811909511 46.7108050264414, 71.4358212095723 45.859747419907904, 73.23649017357046 43.78831473186103 M69.95619502861793 47.561862632974886 C71.1135379226463 46.23049193136291, 72.27088081667466 44.899121229750946, 73.23649017357046 43.78831473186103" stroke="#4c6ef5" stroke-width="0.5" fill="none"></path><path d="M0 0 C28.68456582427025 0, 57.3691316485405 0, 72 0 M0 0 C21.353178030252458 0, 42.706356060504916 0, 72 0 M72 0 C72 15.29855439811945, 72 30.5971087962389, 72 46 M72 0 C72 10.088826654851436, 72 20.177653309702873, 72 46 M72 46 C46.18587675690651 46, 20.37175351381302 46, 0 46 M72 46 C55.007525628805155 46, 38.01505125761032 46, 0 46 M0 46 C0 34.933114741742614, 0 23.86622948348522, 0 0 M0 46 C0 33.28402233272791, 0 20.568044665455815, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1043.0038774082552 1977.5509344581742) rotate(0 40 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">incoming</text></g><g transform="translate(1229.4931932183251 1978.6798043610443) rotate(0 5.5 11.5)"><text x="5.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">0</text></g><g transform="translate(1043.0038774082552 2028.5509344581742) rotate(0 42 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">notify lost</text></g><g transform="translate(1229.4931932183251 2035.6798043610443) rotate(0 5.5 11.5)"><text x="5.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">0</text></g><g transform="translate(1195.4985353132902 1967.6153694096092) rotate(0 52.5 20.5)"><path d="M0 0 C24.69663779810071 0, 49.39327559620142 0, 105 0 M0 0 C32.88236404582858 0, 65.76472809165716 0, 105 0 M105 0 C105 12.499904776364566, 105 24.999809552729133, 105 41 M105 0 C105 11.410576330870391, 105 22.821152661740783, 105 41 M105 41 C67.12486464902759 41, 29.249729298055158 41, 0 41 M105 41 C76.42338036373258 41, 47.846760727465146 41, 0 41 M0 41 C0 28.070744704455137, 0 15.141489408910275, 0 0 M0 41 C0 29.45000053718686, 0 17.90000107437372, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1196.4985353132902 2024.6153694096092) rotate(0 51 22.5)"><path d="M0 0 C23.705919201672078 0, 47.411838403344156 0, 102 0 M0 0 C20.977860300242902 0, 41.955720600485805 0, 102 0 M102 0 C102 11.528187688440084, 102 23.05637537688017, 102 45 M102 0 C102 15.508610609918835, 102 31.01722121983767, 102 45 M102 45 C71.24600254744291 45, 40.492005094885826 45, 0 45 M102 45 C66.05086522847414 45, 30.101730456948275 45, 0 45 M0 45 C0 29.324226681143045, 0 13.64845336228609, 0 0 M0 45 C0 31.80285060033202, 0 18.60570120066404, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1418.120455430812 2182.6533764214173) rotate(0 21.5 11.5)"><text x="21.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">clear</text></g><g transform="translate(1501.303345058886 2172.07664661918) rotate(0 36 23)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C0.965600441736221 4.986216104651257, 2.19265770753389 3.574648192226626, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.6133162138232222 4.241104343583608, 3.4880892517078927 2.084424670091326, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C3.648335235138404 7.997095100192062, 7.163525089409197 3.9533317464551168, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C3.3500231501029547 8.34026389830907, 6.566900919338298 4.639669342689134, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C5.57169766949688 11.881532066893634, 11.271706782187598 5.324421662782372, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C4.36987753206746 13.264067984154451, 8.86806650732876 8.089493497304003, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C6.856252205894873 16.50083345769221, 13.446213650054524 8.919950007526408, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C5.311331628755643 18.27806128129883, 10.356372495776064 12.474405654739646, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C8.394970302828646 20.82775311818362, 16.78510666798352 11.176005311433336, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C6.507872769949093 22.998610501352967, 13.010911602224413 15.517720077772035, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C9.84100486007546 25.261292994600325, 19.938632606538597 13.645301047190852, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C7.544475196613628 27.903148165692713, 15.345573279614934 18.929011389375628, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C11.607492680632955 29.326193560913538, 23.077006042724527 16.132027742964173, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C12.681829312882755 28.090310640453154, 25.225679307224127 13.660261902043398, 36.877284942009794 0.25662288638767805 M1.1886405524609494 47.40872423549325 C12.948784612455563 33.88022604450763, 24.708928672450178 20.351727853522007, 42.520359378862906 -0.13797931854138312 M1.1886405524609494 47.40872423549325 C16.383884466024085 29.928595697312886, 31.579128379587225 12.44846715913252, 42.520359378862906 -0.13797931854138312 M6.831714989314069 47.014122030564195 C16.27626263619843 36.1494127970949, 25.720810283082795 25.284703563625595, 47.50737478672552 0.22212805675232872 M6.831714989314069 47.014122030564195 C22.162332380717757 29.378264120300425, 37.49294977212145 11.742406210036656, 47.50737478672552 0.22212805675232872 M11.818730397176676 47.3742294058579 C22.63473288331568 34.931841853379694, 33.45073536945469 22.489454300901485, 53.15044922357863 -0.1724741481767289 M11.818730397176676 47.3742294058579 C27.60017800282167 29.219750660110254, 43.38162560846666 11.065271914362604, 53.15044922357863 -0.1724741481767289 M17.461804834029795 46.979627200928846 C28.03773077370014 34.813416122822915, 38.61365671337049 22.647205044716983, 58.13746463144125 0.1876332271169865 M17.461804834029795 46.979627200928846 C28.73180183369619 34.01497870303706, 40.001798833362585 21.050330205145276, 58.13746463144125 0.1876332271169865 M22.448820241892403 47.33973457622256 C37.72516161241202 29.76631408565349, 53.00150298293164 12.19289359508442, 63.78053906829436 -0.20696897781207468 M22.448820241892403 47.33973457622256 C37.506818107690144 30.01748955540745, 52.56481597348788 12.69524453459234, 63.78053906829436 -0.20696897781207468 M28.091894678745525 46.9451323712935 C38.80601667841654 34.61994491176037, 49.52013867808756 22.29475745222724, 68.76755447615697 0.1531383974816336 M28.091894678745525 46.9451323712935 C39.37094751487938 33.97006632522858, 50.65000035101323 20.995000279163666, 68.76755447615697 0.1531383974816336 M33.07891008660813 47.30523974658722 C41.875261774474744 37.18619466606027, 50.671613462341355 27.067149585533315, 73.09851085502908 1.2679553529981291 M33.07891008660813 47.30523974658722 C45.35421394435585 33.18411799959606, 57.629517802103564 19.062996252604908, 73.09851085502908 1.2679553529981291 M38.72198452346125 46.91063754165816 C52.548988125867446 31.004489430918987, 66.37599172827363 15.09834132017981, 73.49311305995813 6.911029789851241 M38.72198452346125 46.91063754165816 C50.037153528279696 33.89402459614863, 61.35232253309814 20.8774116506391, 73.49311305995813 6.911029789851241 M43.70899993132386 47.27074491695187 C52.899531906204274 36.69824728749493, 62.09006388108468 26.125749658037993, 73.23165623589668 13.30881380692713 M43.70899993132386 47.27074491695187 C52.95433495201077 36.63520359497965, 62.19966997269768 25.99966227300743, 73.23165623589668 13.30881380692713 M49.35207436817697 46.87614271202281 C56.56838460507855 38.57472739878568, 63.78469484198013 30.273312085548547, 72.97019941183524 19.706597824003016 M49.35207436817697 46.87614271202281 C56.00765249429886 39.219775903940985, 62.66323062042075 31.563409095859154, 72.97019941183524 19.706597824003016 M54.339089776039586 47.23625008731652 C58.72711598403206 42.188403367584165, 63.11514219202454 37.14055664785182, 73.3648016167643 25.34967226085613 M54.339089776039586 47.23625008731652 C58.148177076502364 42.85439639651738, 61.95726437696514 38.47254270571823, 73.3648016167643 25.34967226085613 M59.9821642128927 46.84164788238747 C64.14588211683927 42.05183834910684, 68.30960002078587 37.262028815826206, 73.10334479270284 31.747456277932027 M59.9821642128927 46.84164788238747 C64.17158984037532 42.022264996129415, 68.36101546785792 37.202882109871354, 73.10334479270284 31.747456277932027 M64.96917962075531 47.20175525768118 C67.11690508387139 44.73107973752833, 69.26463054698746 42.26040421737549, 73.49794699763191 37.39053071478514 M64.96917962075531 47.20175525768118 C67.50200064914837 44.28807796547278, 70.03482167754143 41.374400673264375, 73.49794699763191 37.39053071478514 M69.95619502861793 47.561862632974886 C70.7788649183992 46.61548918219853, 71.60153480818046 45.669115731422174, 73.23649017357046 43.78831473186103 M69.95619502861793 47.561862632974886 C71.01649475781093 46.342127322326256, 72.07679448700394 45.12239201167763, 73.23649017357046 43.78831473186103" stroke="#4c6ef5" stroke-width="0.5" fill="none"></path><path d="M0 0 C24.9990046441555 0, 49.998009288311 0, 72 0 M0 0 C18.89581623673439 0, 37.79163247346878 0, 72 0 M72 0 C72 12.982670523226261, 72 25.965341046452522, 72 46 M72 0 C72 17.12471861690283, 72 34.24943723380566, 72 46 M72 46 C51.709999948740005 46, 31.41999989748001 46, 0 46 M72 46 C43.89292697310448 46, 15.785853946208952 46, 0 46 M0 46 C0 36.00459248870611, 0 26.00918497741222, 0 0 M0 46 C0 33.257136107981204, 0 20.514272215962407, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1509.803345058886 2182.57664661918) rotate(0 25 11.5)"><text x="25" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">never</text></g><g transform="translate(1182.2293654670493 2176.6061805114414) rotate(0 71.39795918367349 18.459183673469397)"><path d="M1.672937735915184 -1.6225496381521225 L144.7023351262419 0.6433686167001724 L142.84241510137008 37.36221537571777 L0.9881971925497055 38.18504891377319" stroke="none" stroke-width="0" fill="#fff"></path><path d="M-0.5037814229726791 1.9669316858053207 C33.604280259034475 0.22042079466490105, 61.80305544201819 -0.6517978141913001, 142.04475621088432 0.6515453904867172 M-0.9637814238667488 -0.6931114718317986 C34.712639796779484 -0.3664882219217871, 67.35481266537494 0.17317866917623537, 142.61823804630922 -0.8067768141627312 M141.08415058954643 -0.7424022108316422 C142.32678374701774 10.92371443514616, 143.7166186278466 23.0008265645224, 144.241448200783 38.08895713668693 M143.4214473511188 0.9095756486058235 C143.07612582708353 14.524902024606648, 142.96508976484293 28.620887885470754, 142.61397393002198 36.27843323182691 M140.9726150403826 36.24347144943107 C101.76526391678019 37.67087043235949, 65.58319660665431 39.26389230201892, 1.8075202852487564 35.73005658965934 M142.8144610668628 35.993015675064214 C107.07914770222747 36.24827819009365, 71.14698832929136 35.37344007630886, -0.8270853236317635 36.682710318084844 M0.10155333578586578 34.99943906646598 C-0.3544819420226377 23.263524874451793, 0.09794449154059473 9.050910853336042, -0.45962439477443695 1.4708398431539536 M0.24138277024030685 36.7060696167909 C0.18824374114524345 28.4890349346916, 0.08326541816245536 18.01681989370558, 0.1552075669169426 0.02446264773607254" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1216.8773246507226 2183.0653641849112) rotate(0 5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(1247.3773246507226 2182.5653641849112) rotate(0 5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(1336.3773246507226 2175.5653641849112) rotate(0 17.75 17.75)"><path d="M0.6433686167001724 0.04649673402309418 L35.94384802877903 0.9881971925497055 L36.76668156683445 35.485912665724754 L-0.00971280038356781 34.65341268479824" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0.26330743730068207 -1.8866940587759018 C9.146876802667975 -1.0634566342458127, 20.163121338933706 -1.5647502934560178, 34.20532165467739 0.581592932343483 M0.04875726252794266 -0.43818051367998123 C7.817000098899007 -0.46741115961223845, 13.650375076383353 -0.21332728777080778, 35.575800843536854 0.9825183674693108 M35.06613479554653 0.8927158266305923 C35.65389089290053 9.057142027840019, 36.538813397325576 16.762965323776008, 36.33467184007168 33.94439209997654 M36.10715574771166 0.015097789466381073 C36.60829468693584 12.688683455064893, 35.18296524014324 25.481585221737625, 34.94225139170885 36.41692917793989 M34.94316564500332 36.54884995520115 C29.122550920024516 36.970293610058725, 19.484416053444146 34.214208691082895, -0.16343463957309723 34.34651316702366 M35.653476901352406 35.98350518196821 C24.062812204286455 34.79696834180504, 13.832689804583786 36.223613859154284, -0.6298890635371208 36.12501399964094 M-0.3658539205789566 35.36539973318577 C-0.9488696200028062 24.21011843420565, 1.8114496129378677 12.749554542452096, -0.06487669050693512 0.3372725397348404 M0.6342539265751839 35.57128971070051 C-0.6990090813860297 24.148298732563852, 0.09982834193855522 13.322651199251414, -0.8112748190760612 0.9532083794474602" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1337.3773246507226 2176.5653641849112) rotate(0 17.5 4.5)"><path d="M0.04649673402309418 0.44384802877902985 L35.988197192549706 1.2666815668344498 L34.985912665724754 8.990287199616432 L-0.8465873152017593 7.383707895874977" stroke="none" stroke-width="0" fill="#000"></path><path d="M-1.8866940587759018 -0.6089111715555191 C13.190968293696642 0.6054665889590979, 26.631805084645748 -1.3407571468502284, 35.58159293234348 -1.9275628477334976 M-0.43818051367998123 0.5884241536259651 C7.896429527550936 -0.8238418560475111, 16.22462324798107 0.05873580165207387, 35.98251836746931 -0.85588388890028 M35.40172212198377 0.12855027839541433 C35.62811806760728 2.892684410512447, 35.670513063296674 5.107440338283777, 34.29997644498944 9.56297608539462 M35.00679400525987 0.3534278992563486 C34.929477049857375 3.2306477319449187, 34.89450029328465 6.786249293759465, 35.41261813007295 8.589756751433015 M36.04884995520115 10.036187514662743 C27.488588105887175 7.714243230596185, 15.413571007549763 8.739119348302484, -1.1534868329763412 9.037085399031639 M35.48350518196821 8.278638787567616 C26.911645527929068 8.818059886619448, 21.077021896839142 8.42382785193622, 0.6250139996409416 9.050776667892933 M-0.06057012006640439 8.419734274595976 C-0.18041477613151077 7.825395655632019, -0.4640528004616499 5.297840941697359, 0.15177264288067815 0.21724449321627615 M0.03208036981523038 8.65153135098517 C0.05397928208112715 6.502076148614288, 0.36054686754941934 3.6170622456818817, 0.4289437707513571 0.14475793875753878" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1344.8773246507226 2168.0653641849112) rotate(0 3 7)"><path d="M0.44384802877902985 0.9881971925497055 L7.26668156683445 -0.014087334275245667 L5.990287199616432 13.15341268479824 L-1.6162921041250229 13.963841781020164" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-0.1826733514666557 -0.2253486469388008 C2.5232852697372437 -0.3191359229385853, 4.267239801585675 0.2310787014663219, 5.421731145679951 -0.41586688309907915 M0.17652724608778952 -0.05330409631133079 C2.047652880102396 0.049211896061897256, 4.602112101763487 0.3210463410615921, 5.743234833329916 -0.11136033162474632 M6.1999670997262 1.0118708834052086 C6.789042288511991 4.929835316538812, 6.553899723738432 6.615107794106008, 6.875740577280521 15.273405908048153 M6.549776732176542 -0.1273611061275005 C5.637047924101353 4.19481799826026, 5.694577778875828 9.395025209337474, 5.361843835562468 13.763786435872316 M6.310856254398823 14.542256085574627 C4.41346735060215 13.746896108537912, 3.490890763700008 13.685419448763133, 0.011125619709491774 13.444788996875285 M5.783591636270285 13.75187440291047 C3.919634724408388 14.208878369033336, 1.7916969470679756 14.216514510810375, 0.01523300036787989 13.712160757929087 M-0.9026355728507041 13.678262923657893 C1.0551976646482943 9.447966909408569, -0.019803908914327664 6.657928158342838, 0.3379358783364297 -0.297216822206974 M-0.5420623429119587 14.10864529684186 C-0.07167169630527495 10.138752960413694, -0.6566879230737686 5.77369537129998, 0.22517901584506028 0.016273856908082918" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1359.8773246507226 2168.0653641849112) rotate(0 3 7)"><path d="M0.9881971925497055 1.2666815668344498 L5.985912665724754 -0.00971280038356781 L5.153412684798241 12.383707895874977 L-0.03615821897983551 12.606611624360085" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-0.2253486469388008 0.19546361714601512 C1.5032554864883423 -0.3701361684501171, 3.932462342083454 -0.5600015191733837, 5.5841331169009205 0.4896859243512154 M-0.05330409631133079 -0.24203304424881933 C1.8521754227578642 -0.012565196156501757, 3.9532642252743244 -0.2920706158876419, 5.888639668375253 -0.07456785812973976 M7.011870883405209 0.8194128528237341 C7.140308762341737 4.480564644932747, 4.973564577847719 8.668329291045666, 7.273405908048153 14.176587392389774 M5.8726388938725 -0.44795388057827945 C5.8203442963957785 4.659594020992518, 6.643964115083218 9.461879929155113, 5.7637864358723165 13.335045992583037 M6.542256085574627 13.643506772816181 C4.082480916380883 13.982055233567953, 2.388054563105106 14.042211245149375, -0.5552110031247138 14.209668166935444 M5.751874402910471 13.929302891343832 C4.287781917303801 13.76775160819292, 2.4033319182693957 13.971951327621937, -0.2878392420709133 13.91194599494338 M-0.3217370763421059 15.029587890207768 C-0.7535297621786594 10.010684061050414, 0.2455127964913846 6.450131367146968, -0.297216822206974 0.24677524715662003 M0.10864529684185986 14.017123853415251 C0.5755476480722427 8.3441521294415, 0.6572653061151504 4.049268021434545, 0.016273856908082918 0.1553468100726605" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(1353.3773246507226 2184.5653641849112) rotate(0 0.66275480017066 12.672529354691505)"><path d="M0.6515453904867172 -1.2524558156728745 C-1.2725264270231127 6.03360120985657, -1.802578280903399 9.51591570597142, 2.132286414504051 26.597514525055885 M-0.8067768141627312 0.07640355080366135 C0.3598242185637355 7.77222840782255, -0.44376953955739734 13.207330573685468, 0.25144047290086746 26.283067397773266" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(1343.8773246507226 2183.5653641849112) rotate(0 -0.32747064530849457 13.575839783996344)"><path d="M-1.2524558156728745 -1.294678345322609 C0.6112074511498213 5.61833264861256, -1.2218312041461468 16.725706270672383, 0.5975145250558853 27.123638972640038 M0.07640355080366135 0.07580084353685379 C1.1121890852600336 9.195737625323238, -0.06210917994379994 19.85064961727709, 0.28306739777326584 28.446357913315296" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(1363.3773246507226 2185.0653641849112) rotate(0 0.3258397839963436 13.629220619797707)"><path d="M-1.294678345322609 0.581592932343483 C-1.4508279721811415 5.315438725464046, 2.5026841283217074 13.491444444693625, 0.6236389726400375 26.67684830725193 M0.07580084353685379 0.9825183674693108 C-0.6382640246674418 6.8245680226758125, 0.39240828897804025 14.175751707218588, 1.9463579133152962 25.64283364266157" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(1372.3773246507226 2193.0653641849112) rotate(0 -16.43732399493456 -0.6023989655077457)"><path d="M0.581592932343483 -1.9275628477334976 C-12.693850107491016 1.4121910957992077, -22.517739802598953 -1.096456346064806, -32.82315169274807 -0.35536064207553864 M0.9825183674693108 -0.85588388890028 C-7.8281599372625355 -0.22278724029660224, -15.130850265920163 0.47213020011782647, -33.85716635733843 0.7227649167180061" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(1371.8773246507226 2202.0653641849112) rotate(0 -18.60562226548791 0.0995359756052494)"><path d="M-1.9275628477334976 -1.386222943663597 C-6.919766509011389 0.43957846209406853, -17.973993482664227 1.7562894535064697, -36.35536064207554 -0.6135536283254623 M-0.85588388890028 -0.3712011054158211 C-11.322854301556944 0.4444143651425838, -21.702989644035696 1.1118209651112556, -35.277235083281994 1.585294894874096" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(919.1800970778143 2588.468754522708) rotate(0 412 242.19444444444457)"><path d="M0 0 C280.227407926321 0, 560.454815852642 0, 824 0 M0 0 C238.9694912016392 0, 477.9389824032784 0, 824 0 M824 0 C824 136.2877507086844, 824 272.5755014173688, 824 484.38888888888914 M824 0 C824 153.1982566141835, 824 306.396513228367, 824 484.38888888888914 M824 484.38888888888914 C619.1304369986058 484.38888888888914, 414.26087399721143 484.38888888888914, 0 484.38888888888914 M824 484.38888888888914 C639.4241226136685 484.38888888888914, 454.84824522733686 484.38888888888914, 0 484.38888888888914 M0 484.38888888888914 C0 332.7260584450846, 0 181.06322800128004, 0 0 M0 484.38888888888914 C0 361.3100231517936, 0 238.23115741469806, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1012.180097077814 2658.468754522708) rotate(0 25 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Stock</text></g><g transform="translate(1049.5967637444805 2842.6195481735012) rotate(0 227.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">current stock will change from 15 to 17 after update</text></g><g transform="translate(1009.2526079003255 2961.9681914365974) rotate(0 288.5 28.5)"><path d="M0 0 C210.21055428311226 0, 420.4211085662245 0, 576.9999999999999 0 M0 0 C145.5924633927643 0, 291.1849267855286 0, 576.9999999999999 0 M576.9999999999999 0 C576.9999999999999 13.76067228242755, 576.9999999999999 27.5213445648551, 576.9999999999999 57 M576.9999999999999 0 C576.9999999999999 14.453476584702731, 576.9999999999999 28.906953169405462, 576.9999999999999 57 M576.9999999999999 57 C439.1269875355064 57, 301.2539750710129 57, 0 57 M576.9999999999999 57 C399.0728687815367 57, 221.14573756307357 57, 0 57 M0 57 C0 35.215562392026186, 0 13.431124784052372, 0 0 M0 57 C0 44.99653309509158, 0 32.99306619018316, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1504.252607900325 2961.9681914365974) rotate(0 41 29)"><path d="M0 0 C25.931014920771123 0, 51.862029841542245 0, 82 0 M0 0 C21.203527615964415 0, 42.40705523192883 0, 82 0 M82 0 C82 20.769845850765705, 82 41.53969170153141, 82 58 M82 0 C82 15.434329311549666, 82 30.868658623099332, 82 58 M82 58 C60.65659751743078 58, 39.313195034861565 58, 0 58 M82 58 C54.86310951858759 58, 27.726219037175177 58, 0 58 M0 58 C0 37.05103646963835, 0 16.102072939276695, 0 0 M0 58 C0 43.39726181775331, 0 28.794523635506625, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(1543.252607900325 2973.9681914365974) rotate(0 0 17)"><path d="M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34 M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1543.252607900325 2973.9681914365974) rotate(0 0 17)"><path d="M-5.814342436536368 18.025225446639556 C-4.479791978043323 21.69187269647201, -3.1452415195502788 25.358519946304465, 0 34 M-5.814342436536368 18.025225446639556 C-4.092619901678256 22.755619233728396, -2.370897366820143 27.486013020817232, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1543.252607900325 2973.9681914365974) rotate(0 0 17)"><path d="M5.814342436536368 18.025225446639556 C4.479791978043323 21.69187269647201, 3.1452415195502788 25.358519946304465, 0 34 M5.814342436536368 18.025225446639556 C4.092619901678256 22.755619233728396, 2.370897366820143 27.486013020817232, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(1040.238523322765 2977.9681914365974) rotate(0 35.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">address</text></g><g transform="translate(924.8979747308113 2517.6019687952994) rotate(0 275 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"># updating product: updating stock</text></g><g transform="translate(1060.2653209606888 2913.4520033282333) rotate(0 54 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">next restock</text></g><g transform="translate(1414.979606674974 2904.6662890425177) rotate(0 36 23)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.0694736183042561 4.8667236839697, 2.4004040606699606 3.335663350863511, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.441522668299273 4.438730210918843, 3.1445021606599943 2.4796764047617965, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C2.449943352066549 9.375687261948018, 4.766741323265487 6.71051606996703, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C3.270109001809981 8.432194609795282, 6.407072622752351 4.823530765661556, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C4.9077817690326295 12.645279943839396, 9.943874981259098 6.851917416673896, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C5.511206114358018 11.951119640829049, 11.150723671909875 5.4635968106532005, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C7.673260726100951 15.56097266761675, 15.08023069046668 7.040228427375489, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C8.553656316296054 14.54819339479961, 16.841021870856885 5.014669881741206, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C9.240123310904831 19.855515798424975, 18.47541268413589 9.231530671916044, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C8.74180051347356 20.428770601187903, 17.478767089273347 10.378040277441904, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C7.938773350425098 27.449560026522423, 16.134169587237874 18.021835111035053, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C7.911517967119886 27.48091375840344, 16.07965882062745 18.084542574797084, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C14.102280369671952 26.456268620719165, 28.06658142080252 10.392177862575423, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C11.953988300397254 28.927595946696226, 23.769997282253126 15.334832514529545, 36.877284942009794 0.25662288638767805 M1.1886405524609494 47.40872423549325 C13.63346182153386 33.0925950140397, 26.07828309060677 18.776465792586155, 42.520359378862906 -0.13797931854138312 M1.1886405524609494 47.40872423549325 C13.834373281759817 32.861472817547124, 26.480106011058684 18.314221399600996, 42.520359378862906 -0.13797931854138312 M6.831714989314069 47.014122030564195 C19.934335677402537 31.941281139186813, 33.03695636549101 16.86844024780943, 47.50737478672552 0.22212805675232872 M6.831714989314069 47.014122030564195 C19.423769074466428 32.52862082898667, 32.01582315961879 18.043119627409144, 47.50737478672552 0.22212805675232872 M11.818730397176676 47.3742294058579 C26.401377920165906 30.59881240177138, 40.98402544315514 13.823395397684855, 53.15044922357863 -0.1724741481767289 M11.818730397176676 47.3742294058579 C23.885941807439863 33.49249063623425, 35.95315321770305 19.61075186661059, 53.15044922357863 -0.1724741481767289 M17.461804834029795 46.979627200928846 C33.05256944474344 29.04450414834451, 48.64333405545709 11.109381095760178, 58.13746463144125 0.1876332271169865 M17.461804834029795 46.979627200928846 C33.514412316278964 28.51321469982981, 49.567019798528136 10.046802198730774, 58.13746463144125 0.1876332271169865 M22.448820241892403 47.33973457622256 C37.292288074414145 30.264278128088236, 52.135755906935884 13.18882167995391, 63.78053906829436 -0.20696897781207468 M22.448820241892403 47.33973457622256 C33.45126223718552 34.68287290255567, 44.453704232478636 22.02601122888878, 63.78053906829436 -0.20696897781207468 M28.091894678745525 46.9451323712935 C38.520159473394585 34.94878600939413, 48.94842426804365 22.952439647494757, 68.76755447615697 0.1531383974816336 M28.091894678745525 46.9451323712935 C43.84148948937288 28.827296074615823, 59.59108430000025 10.70945977793815, 68.76755447615697 0.1531383974816336 M33.07891008660813 47.30523974658722 C47.34793195115798 30.89060779166325, 61.61695381570783 14.47597583673928, 73.09851085502908 1.2679553529981291 M33.07891008660813 47.30523974658722 C48.8976173679153 29.107898647094505, 64.71632464922247 10.91055754760179, 73.09851085502908 1.2679553529981291 M38.72198452346125 46.91063754165816 C49.905834415763785 34.045089954451235, 61.08968430806631 21.17954236724431, 73.49311305995813 6.911029789851241 M38.72198452346125 46.91063754165816 C46.02654066942349 38.507706922571145, 53.33109681538572 30.10477630348413, 73.49311305995813 6.911029789851241 M43.70899993132386 47.27074491695187 C51.65369853686655 38.13141463624275, 59.59839714240923 28.99208435553363, 73.23165623589668 13.30881380692713 M43.70899993132386 47.27074491695187 C54.28661543049228 35.10259022297723, 64.8642309296607 22.93443552900258, 73.23165623589668 13.30881380692713 M49.35207436817697 46.87614271202281 C55.18257527926562 40.168918665633115, 61.013076190354276 33.46169461924342, 72.97019941183524 19.706597824003016 M49.35207436817697 46.87614271202281 C56.40510873276693 38.76255480395442, 63.45814309735688 30.64896689588603, 72.97019941183524 19.706597824003016 M54.339089776039586 47.23625008731652 C60.20503176150179 40.48825574864951, 66.070973746964 33.7402614099825, 73.3648016167643 25.34967226085613 M54.339089776039586 47.23625008731652 C60.938011574559695 39.64505892857694, 67.5369333730798 32.05386776983735, 73.3648016167643 25.34967226085613 M59.9821642128927 46.84164788238747 C65.06426690316256 40.99535750524812, 70.14636959343241 35.149067128108776, 73.10334479270284 31.747456277932027 M59.9821642128927 46.84164788238747 C62.61570580044832 43.81210484096082, 65.24924738800394 40.78256179953418, 73.10334479270284 31.747456277932027 M64.96917962075531 47.20175525768118 C68.15218823756568 43.54012270499029, 71.33519685437605 39.87849015229939, 73.49794699763191 37.39053071478514 M64.96917962075531 47.20175525768118 C67.22962937584751 44.60140527331265, 69.49007913093969 42.00105528894413, 73.49794699763191 37.39053071478514 M69.95619502861793 47.561862632974886 C71.22166828660232 46.106102176806594, 72.48714154458672 44.6503417206383, 73.23649017357046 43.78831473186103 M69.95619502861793 47.561862632974886 C71.19178496651935 46.140479004132914, 72.42737490442077 44.71909537529095, 73.23649017357046 43.78831473186103" stroke="#4c6ef5" stroke-width="0.5" fill="none"></path><path d="M0 0 C15.607046788930894 0, 31.21409357786179 0, 72 0 M0 0 C27.95016422867775 0, 55.9003284573555 0, 72 0 M72 0 C72 15.406367994844913, 72 30.812735989689827, 72 46 M72 0 C72 16.16315798610449, 72 32.32631597220898, 72 46 M72 46 C57.02690897583962 46, 42.05381795167923 46, 0 46 M72 46 C54.47378405928612 46, 36.947568118572235 46, 0 46 M0 46 C0 36.32309472411871, 0 26.64618944823742, 0 0 M0 46 C0 33.51145796924829, 0 21.022915938496585, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1045.6130286524176 2712.5638470792755) rotate(0 40 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">incoming</text></g><g transform="translate(1232.1023444624875 2713.6927169821456) rotate(0 5.5 11.5)"><text x="5.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">3</text></g><g transform="translate(1045.6130286524176 2763.5638470792755) rotate(0 42 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">notify lost</text></g><g transform="translate(1232.1023444624875 2770.6927169821456) rotate(0 5.5 11.5)"><text x="5.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">1</text></g><g transform="translate(1198.1076865574526 2702.6282820307106) rotate(0 52.5 20.5)"><path d="M0 0 C26.49429576471448 0, 52.98859152942896 0, 105 0 M0 0 C25.34860683605075 0, 50.6972136721015 0, 105 0 M105 0 C105 10.39636035040021, 105 20.79272070080042, 105 41 M105 0 C105 9.796869169920683, 105 19.593738339841366, 105 41 M105 41 C72.62157924100757 41, 40.24315848201513 41, 0 41 M105 41 C64.87077282741666 41, 24.741545654833317 41, 0 41 M0 41 C0 32.36592731401324, 0 23.731854628026486, 0 0 M0 41 C0 29.648827327042817, 0 18.297654654085633, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1199.1076865574526 2759.6282820307106) rotate(0 51 22.5)"><path d="M0 0 C26.37511971741915 0, 52.7502394348383 0, 102 0 M0 0 C36.526280634105206 0, 73.05256126821041 0, 102 0 M102 0 C102 11.974910672754051, 102 23.949821345508102, 102 45 M102 0 C102 11.71284282580018, 102 23.42568565160036, 102 45 M102 45 C68.24435574263333 45, 34.48871148526668 45, 0 45 M102 45 C65.15871930867434 45, 28.31743861734867 45, 0 45 M0 45 C0 33.67028934136033, 0 22.340578682720658, 0 0 M0 45 C0 35.718918677419424, 0 26.437837354838848, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1431.979606674974 2915.1662890425177) rotate(0 21.5 11.5)"><text x="21.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">clear</text></g><g transform="translate(1515.162496303048 2904.5895592402812) rotate(0 36 23)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.3753640436643175 4.514837002564089, 3.0121849113900834 2.6318899880522895, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C0.8493351942651193 5.119963972199745, 1.9601272125916869 3.842143927323601, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C3.034463156220709 8.70327414585406, 5.935780931573807 5.365689837779114, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C2.961258922947706 8.78748598308616, 5.789372465027801 5.534113512243313, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C5.4253787671312494 12.049852709554312, 10.979068977456338 5.661062948103725, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C5.178774409341544 12.333538571838613, 10.485860261876928 6.22843467267233, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C7.788121109505969 15.428840911306326, 15.309951457276716 6.775964914754638, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C5.330556112387134 18.255946042684027, 10.394821463039046 12.430175177510039, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C6.3299650457229895 23.203269926703264, 12.655096153772206 15.92703892847263, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C8.944233705451841 20.19589785256318, 17.88363347322991 9.912294780192461, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C11.134114539684509 23.77374047210639, 22.524851965756696 10.670196002202985, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C7.814464994959845 27.59256043140325, 15.885552876307369 18.30783592079671, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C12.337943974365544 28.48590546958986, 24.537908630189705 14.451451560316809, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C13.741365245342406 26.87145397743612, 27.34475117214343 11.22254857600933, 36.877284942009794 0.25662288638767805 M1.1886405524609494 47.40872423549325 C16.215279177930732 30.122553894025874, 31.24191780340052 12.836383552558495, 42.520359378862906 -0.13797931854138312 M1.1886405524609494 47.40872423549325 C9.581212113384062 37.75417505646579, 17.973783674307175 28.099625877438324, 42.520359378862906 -0.13797931854138312 M6.831714989314069 47.014122030564195 C17.757773431649383 34.445129583051255, 28.6838318739847 21.876137135538308, 47.50737478672552 0.22212805675232872 M6.831714989314069 47.014122030564195 C18.475860205318625 33.6190652449789, 30.120005421323178 20.2240084593936, 47.50737478672552 0.22212805675232872 M11.818730397176676 47.3742294058579 C27.21453877819911 29.663377840701255, 42.61034715922155 11.952526275544606, 53.15044922357863 -0.1724741481767289 M11.818730397176676 47.3742294058579 C24.78789339673942 32.45491402306125, 37.75705639630217 17.535598640264602, 53.15044922357863 -0.1724741481767289 M17.461804834029795 46.979627200928846 C32.95671218411056 29.154775312579325, 48.45161953419132 11.329923424229804, 58.13746463144125 0.1876332271169865 M17.461804834029795 46.979627200928846 C28.098486788354222 34.7435243230162, 38.73516874267865 22.50742144510356, 58.13746463144125 0.1876332271169865 M22.448820241892403 47.33973457622256 C32.99473548210508 35.20804685865133, 43.54065072231776 23.076359141080104, 63.78053906829436 -0.20696897781207468 M22.448820241892403 47.33973457622256 C35.35900949885364 32.488260723770274, 48.26919875581487 17.636786871317987, 63.78053906829436 -0.20696897781207468 M28.091894678745525 46.9451323712935 C39.758227506288875 33.52455165836228, 51.424560333832225 20.103970945431055, 68.76755447615697 0.1531383974816336 M28.091894678745525 46.9451323712935 C43.60212757494806 29.102650458862083, 59.11236047115059 11.26016854643067, 68.76755447615697 0.1531383974816336 M33.07891008660813 47.30523974658722 C48.00875136482454 30.130422015302933, 62.93859264304095 12.955604284018648, 73.09851085502908 1.2679553529981291 M33.07891008660813 47.30523974658722 C42.69862404602975 36.23902472116566, 52.318338005451366 25.17280969574411, 73.09851085502908 1.2679553529981291 M38.72198452346125 46.91063754165816 C48.85826304400882 35.25018296482732, 58.9945415645564 23.589728387996466, 73.49311305995813 6.911029789851241 M38.72198452346125 46.91063754165816 C47.190995580249954 37.16815478152302, 55.66000663703865 27.425672021387886, 73.49311305995813 6.911029789851241 M43.70899993132386 47.27074491695187 C54.787307700832244 34.52660965343837, 65.86561547034063 21.782474389924868, 73.23165623589668 13.30881380692713 M43.70899993132386 47.27074491695187 C51.14701488272454 38.71428750442301, 58.585029834125216 30.15783009189416, 73.23165623589668 13.30881380692713 M49.35207436817697 46.87614271202281 C58.51149848727816 36.33943057707068, 67.67092260637935 25.80271844211855, 72.97019941183524 19.706597824003016 M49.35207436817697 46.87614271202281 C57.82154168796805 37.133135081344356, 66.29100900775913 27.390127450665904, 72.97019941183524 19.706597824003016 M54.339089776039586 47.23625008731652 C61.9156957815482 38.52036190461843, 69.49230178705682 29.80447372192035, 73.3648016167643 25.34967226085613 M54.339089776039586 47.23625008731652 C58.40411740517944 42.559970728273505, 62.4691450343193 37.88369136923049, 73.3648016167643 25.34967226085613 M59.9821642128927 46.84164788238747 C63.34098199809981 42.97777001667317, 66.69979978330691 39.11389215095886, 73.10334479270284 31.747456277932027 M59.9821642128927 46.84164788238747 C64.5650515727087 41.569639049802646, 69.14793893252468 36.29763021721783, 73.10334479270284 31.747456277932027 M64.96917962075531 47.20175525768118 C67.23811460726664 44.59164413116013, 69.50704959377795 41.98153300463908, 73.49794699763191 37.39053071478514 M64.96917962075531 47.20175525768118 C67.56727982892488 44.21298285940858, 70.16538003709445 41.22421046113598, 73.49794699763191 37.39053071478514 M69.95619502861793 47.561862632974886 C70.82153976332255 46.566397388815645, 71.68688449802717 45.570932144656396, 73.23649017357046 43.78831473186103 M69.95619502861793 47.561862632974886 C71.10737221247501 46.23758476955204, 72.2585493963321 44.9133069061292, 73.23649017357046 43.78831473186103" stroke="#4c6ef5" stroke-width="0.5" fill="none"></path><path d="M0 0 C17.131241887807846 0, 34.26248377561569 0, 72 0 M0 0 C16.469169813394547 0, 32.938339626789094 0, 72 0 M72 0 C72 17.891359259188174, 72 35.78271851837635, 72 46 M72 0 C72 16.85603842586279, 72 33.71207685172558, 72 46 M72 46 C50.652469736337665 46, 29.304939472675322 46, 0 46 M72 46 C44.20580386519432 46, 16.41160773038864 46, 0 46 M0 46 C0 34.4678519949317, 0 22.935703989863395, 0 0 M0 46 C0 30.86363368183374, 0 15.727267363667483, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1523.662496303048 2915.0895592402812) rotate(0 25 11.5)"><text x="25" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">never</text></g><g transform="translate(1196.0885167112117 2909.119093132542) rotate(0 71.39795918367349 18.459183673469397)"><path d="M-1.1418243795633316 -1.0046259015798569 L144.4990232060759 -1.426329717040062 L144.43414712651656 35.85880122166503 L1.6835669130086899 36.37682518940795" stroke="none" stroke-width="0" fill="#fff"></path><path d="M-0.3727961629629135 0.7564176172018051 C36.729751035495084 -0.37391743593526106, 72.55191798492964 0.4629704005210378, 141.37068775995658 -1.3066493421792984 M0.16271203011274338 0.27240557223558426 C33.05778231309082 -1.5164845041489725, 67.19790111901811 -0.5159411482072, 143.68534429325746 -0.5211303755640984 M141.7684805761187 0.5503796190023422 C142.3601679568647 11.758133697312084, 142.19128701738106 24.685477009020264, 144.12463072641776 35.19265205245841 M142.03591687931703 -0.03182869404554367 C142.0532299560963 14.845505480909212, 142.76549711651194 29.45545226572725, 142.76085312618898 36.28411140870679 M143.05794600351737 37.254392927702554 C102.65255512438566 38.71467735192449, 63.151354308730504 38.18086816689642, 1.720610037446022 36.485484903868326 M142.3368285442798 36.1935180706941 C98.39024040980306 35.308574170508216, 51.90110314202552 35.750081271567176, -0.49301130324602127 36.76974835824598 M-1.9394584745168686 37.318343943174966 C-0.6244689786692664 25.33277080455906, -1.769820865418534 14.929091586841594, 0.5810288339853287 -1.157154694199562 M0.27907007187604904 37.90980687570203 C-0.48869153535335613 27.076435881016785, 0.3116646143201058 17.86483765244482, -0.028601713478565216 -0.6333113238215446" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1230.736475894885 2915.5782768060126) rotate(0 5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(1261.236475894885 2915.0782768060126) rotate(0 5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(1350.236475894885 2908.0782768060126) rotate(0 17.75 17.75)"><path d="M-1.426329717040062 1.6382287591695786 L34.440433874726295 1.6835669130086899 L34.958457842469215 34.71851383149624 L0.8811601549386978 33.981839045882225" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-1.1716939359903336 1.1620158106088638 C9.653480711206795 -1.6089075982198118, 18.66992427930236 -1.4540733277425169, 36.198420867323875 1.4736865907907486 M-0.46430235356092453 -0.33890873938798904 C11.763868709281088 1.1416969546303153, 21.93412503823638 0.767912174127996, 36.01372999697924 0.26068418473005295 M34.278960570693016 -0.794292077422142 C34.32482313815504 10.155010279640555, 33.87197708789259 19.649615981429815, 33.65919195115566 33.854674234986305 M35.58365911990404 0.30937688797712326 C35.42046035733074 7.916929476335645, 34.85444487538189 15.735595040768386, 34.934196658432484 35.606899194419384 M37.1436623185873 36.723780527710915 C25.494754079356788 37.27222864385694, 12.836919448524714 35.88320915456861, -1.7926498800516129 34.497640028595924 M34.60587138682604 35.017713479697704 C26.027147359773515 35.291196866966786, 17.310918755084277 35.79700498197228, -0.285099558532238 35.459210090339184 M-0.46284259855747223 33.624925032258034 C0.18523628171533346 28.873567626252772, -1.2281505400314927 20.07083387747407, 1.4420164674520493 -0.423099622130394 M-0.6386323496699333 36.077849082648754 C-0.9988924947008491 23.83069953136146, -0.9852723565325141 11.647690299898386, -0.5023129507899284 0.8515524193644524" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1351.236475894885 2909.0782768060126) rotate(0 17.5 4.5)"><path d="M1.6382287591695786 -1.0595661252737045 L36.68356691300869 -0.5415421575307846 L34.21851383149624 9.881160154938698 L-1.518160954117775 9.852583780884743" stroke="none" stroke-width="0" fill="#000"></path><path d="M1.1620158106088638 -0.33480609953403473 C10.398500222712755 -1.10160290338099, 22.37706532329321 0.9034673061221838, 36.47368659079075 0.32542406022548676 M-0.33890873938798904 0.5362410023808479 C12.342845428735018 -0.35862455181777475, 23.422480151057243 0.6762358207255602, 35.26068418473005 -0.5137188956141472 M34.64256856516003 -0.5727911598980426 C35.56977706037462 2.1710989460349084, 35.87051556192338 5.0669780351221565, 34.25960340574384 8.315998660773039 M35.13921959958971 -0.030708205327391602 C34.947960516959434 2.3859390031546357, 34.88796239808202 5.08809684701264, 35.04810463748872 9.058956218138338 M36.223780527710915 10.109853133559227 C25.632565271109343 8.854758462682366, 13.15550101548433 7.4949910257011645, -1.0023599714040756 8.081820353865623 M34.517713479697704 8.547378487884998 C26.54396116361022 8.538435996696354, 19.086741745471954 8.401955426856876, -0.04078990966081619 8.030270762741566 M-0.8437837354838849 9.115304457396268 C0.29430051393806944 5.599290919303893, -0.42357212953269485 3.888928473740816, -0.1903948299586773 0.25116306468844407 M0.2600320871919393 8.708880842104554 C0.007154864966869359 5.12271432839334, -0.23688484936952597 1.5893680203706027, 0.38319858871400353 -0.320924186334014" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1358.736475894885 2900.5782768060126) rotate(0 3 7)"><path d="M-1.0595661252737045 1.6835669130086899 L5.458457842469215 -0.7814861685037613 L6.881160154938698 12.481839045882225 L0.8525837808847427 13.071687087416649" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-0.10044182986021044 -0.42756918221712115 C1.7184451818466187 -0.41597937539219854, 4.430406229197979 0.40724550291895867, 6.097627218067646 0.16344334334135058 M0.16087230071425435 0.26682777777314187 C1.2172873176634313 0.1750268679857254, 2.9013718597590925 0.09853977978229525, 5.845884331315756 0.08255694285035131 M5.108991529047489 0.9300986513495446 C4.706526533812285 5.160126301646233, 4.6259616057574755 6.372696371376515, 4.93599791675806 13.955439828336239 M5.952231680601836 -0.024545668810606047 C5.5677331200242035 3.5180775426328186, 5.615649937689304 7.3467366732656965, 6.091709672659635 14.117608953267336 M6.332955940067768 14.516183011233807 C3.982892552018165 14.136190580278635, 1.6877196058630939 13.736005424410104, -0.27545389384031294 13.565090434253216 M5.8642135463655 13.852096609026194 C3.6750624664127827 13.974901852309705, 1.3537664584815499 13.958825835883617, -0.2909187711775303 14.059996489435434 M0.17936248928308496 14.40672018378973 C-0.7776093040406704 9.600835561752318, 1.0418105091154577 6.325442577898501, 0.3906981006264687 1.3880153402686117 M-0.4528520233929157 13.979978800565004 C-0.3539093977212906 9.711871360987423, -0.26221053659915916 6.819106481224297, -0.4992154009640216 0.5733800657093524" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1373.7364758948847 2900.5782768060126) rotate(0 3 7)"><path d="M1.6835669130086899 -0.5415421575307846 L5.218513831496239 0.8811601549386978 L4.481839045882225 14.852583780884743 L-0.9283129125833511 15.40739668905735" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-0.42756918221712115 -0.3919948026537895 C1.0673729181289673 0.21957044318318364, 3.3390896156430245 0.10767140105366711, 6.163443343341351 -0.4263735696673393 M0.26682777777314187 -0.1563391126692295 C1.6761109314858915 0.1219445389509201, 3.1210424311459066 -0.186290128827095, 6.082556942850351 -0.09381167069077492 M6.930098651349544 -1.2080007061362266 C7.342313652783632 2.0567067652940754, 4.792671519070863 5.626542715728283, 5.955439828336239 13.435953618586064 M5.975454331189394 -0.4439791567623615 C5.925436688363552 3.921060428768396, 6.118142200410366 8.725955208390952, 6.117608953267336 14.10178316757083 M6.516183011233807 13.870135267078876 C3.8063784688711166 13.495500629991293, 1.1130946174263954 13.757841700166464, -0.4349095657467842 14.48035183697939 M5.852096609026193 13.955414303392171 C4.740316211432219 13.88731284171343, 3.460717362910509 13.68192393809557, 0.05999648943543434 13.890541537851096 M0.40672018378973007 13.189991714060307 C-0.578715347200632 11.133401346206664, -0.16491448774933815 6.638677738606929, 1.3880153402686117 -0.3115098938345908 M-0.020021199434995696 13.556682073324918 C-0.48053740441799164 10.342466223984957, 0.5151878219842909 6.888955178111791, 0.5733800657093524 -0.37084814384579656" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(1367.236475894885 2917.0782768060126) rotate(0 -0.5165169888082914 12.3095419742167)"><path d="M-1.3066493421792984 -1.2703963369131088 C0.8331094544008374 10.96692061636597, 0.6391630425676703 19.527716119103133, -0.9212452322244644 25.57139529287815 M-0.5211303755640984 0.5156411454081535 C0.7888884256407619 7.308128895722331, -0.10550590392202136 14.37452636111528, 0.18729443103075027 25.889480285346508" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(1357.736475894885 2916.0782768060126) rotate(0 -0.308343032559776 14.058291979134083)"><path d="M-1.2703963369131088 0.6984208673238754 C1.415784153267741 8.259962144233288, 0.6285385544598103 14.44456431243569, -0.42860470712184906 27.322182521224022 M0.5156411454081535 0.5137299969792366 C0.6865354941040278 9.390361562930048, 0.8778531689941884 19.492849696241322, -0.11051971465349197 27.60285396128893" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(1377.2364758948847 2917.5782768060126) rotate(0 0.5400990881577172 13.416583094745874)"><path d="M0.6984208673238754 1.4736865907907486 C0.5019339735433459 6.387170092575253, -0.9016276144608855 10.74658521655947, 0.8221825212240219 26.572482004761696 M0.5137299969792366 0.26068418473005295 C-0.06319325249642127 10.185491303391755, 0.721233963035047 19.217817890308798, 1.102853961288929 24.863565377891064" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(1386.2364758948847 2925.5782768060126) rotate(0 -16.581374015659094 0.6196436536490637)"><path d="M1.4736865907907486 0.32542406022548676 C-7.433884973824025 -1.3025136847794057, -16.885996943712236 -0.5590859313309193, -32.927517995238304 1.7788518518209457 M0.26068418473005295 -0.5137188956141472 C-8.152966913580896 -0.13803736999630928, -17.466833160817625 -0.22247783973813057, -34.636434622108936 0.664356179535389" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(1385.7364758948847 2934.5782768060126) rotate(0 -17.505109880119562 0.33789916107161844)"><path d="M0.32542406022548676 0.5448111444711685 C-9.93103972144425 -0.42686093762516975, -17.70089856155217 1.8107059574127198, -34.221148148179054 -0.042260751128196716 M-0.5137188956141472 0.2751898095011711 C-12.96387639246881 -0.16510929360985754, -25.704624985679985 0.16053991347551344, -35.33564382046461 0.1371423527598381" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(1830.430097077814 2584.8713272638206) rotate(0 412 257.81944444444457)"><path d="M0 0 C289.3018495619297 0, 578.6036991238594 0, 824 0 M0 0 C266.4378617227078 0, 532.8757234454156 0, 824 0 M824 0 C824 168.13916297101736, 824 336.2783259420347, 824 515.6388888888891 M824 0 C824 103.9498607670889, 824 207.8997215341778, 824 515.6388888888891 M824 515.6388888888891 C509.1749795854091 515.6388888888891, 194.34995917081824 515.6388888888891, 0 515.6388888888891 M824 515.6388888888891 C495.227893358469 515.6388888888891, 166.45578671693795 515.6388888888891, 0 515.6388888888891 M0 515.6388888888891 C0 387.63720168262324, 0 259.63551447635734, 0 0 M0 515.6388888888891 C0 312.98472778310804, 0 110.330566677327, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1923.430097077814 2654.8713272638206) rotate(0 25 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Stock</text></g><g transform="translate(1957.8467637444805 2719.272120914614) rotate(0 31 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">current</text></g><g transform="translate(1909.2526079003255 3004.620764177708) rotate(0 288.5 28.5)"><path d="M0 0 C192.039151353389 0, 384.078302706778 0, 576.9999999999999 0 M0 0 C136.73794285580513 0, 273.47588571161026 0, 576.9999999999999 0 M576.9999999999999 0 C576.9999999999999 22.734716738015415, 576.9999999999999 45.46943347603083, 576.9999999999999 57 M576.9999999999999 0 C576.9999999999999 19.196387576311828, 576.9999999999999 38.392775152623656, 576.9999999999999 57 M576.9999999999999 57 C404.0372541241347 57, 231.07450824826947 57, 0 57 M576.9999999999999 57 C368.86377132609476 57, 160.72754265218964 57, 0 57 M0 57 C0 41.1177114598453, 0 25.235422919690603, 0 0 M0 57 C0 44.01384368017316, 0 31.027687360346317, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2404.252607900325 3004.620764177708) rotate(0 41 29)"><path d="M0 0 C26.443931220471864 0, 52.88786244094373 0, 82 0 M0 0 C24.761952497065067 0, 49.523904994130135 0, 82 0 M82 0 C82 18.225900404155254, 82 36.45180080831051, 82 58 M82 0 C82 14.270743449032308, 82 28.541486898064615, 82 58 M82 58 C64.16376731544733 58, 46.32753463089466 58, 0 58 M82 58 C50.749854277074334 58, 19.49970855414867 58, 0 58 M0 58 C0 42.38057781010866, 0 26.761155620217323, 0 0 M0 58 C0 43.396501176059246, 0 28.793002352118492, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(2443.252607900325 3016.620764177708) rotate(0 0 17)"><path d="M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34 M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2443.252607900325 3016.620764177708) rotate(0 0 17)"><path d="M-5.814342436536368 18.025225446639556 C-3.672683048188459 23.909386256288435, -1.5310236598405504 29.79354706593731, 0 34 M-5.814342436536368 18.025225446639556 C-4.438116949352489 21.8063738967552, -3.0618914621686106 25.587522346870845, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2443.252607900325 3016.620764177708) rotate(0 0 17)"><path d="M5.814342436536368 18.025225446639556 C3.672683048188459 23.909386256288435, 1.5310236598405504 29.79354706593731, 0 34 M5.814342436536368 18.025225446639556 C4.438116949352489 21.8063738967552, 3.0618914621686106 25.587522346870845, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(1940.238523322765 3020.620764177708) rotate(0 35.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">address</text></g><g transform="translate(2138.8360795545505 2714.400990817485) rotate(0 11 11.5)"><text x="11" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">15</text></g><g transform="translate(1960.2653209606888 2956.104576069344) rotate(0 54 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">next restock</text></g><g transform="translate(2314.979606674974 2947.3188617836304) rotate(0 36 23)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.6911573955638532 4.151558307328436, 3.643771615189155 1.9053325975809834, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C0.7997554922365635 5.176998895052827, 1.8609678085345753 3.956213773029765, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C4.062912716240784 7.520178263586619, 7.992680051613957 2.999498073244231, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C4.049132298871088 7.536030820367036, 7.965119216874566 3.0312031868050653, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C4.8136656135422236 12.75354819572466, 9.755642670278286 7.068453920444423, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C3.449655413071555 14.322662437473312, 7.027622269336949 10.206682403941727, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C5.600209395927803 17.945745424395433, 10.934128030120384 11.80977394093285, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C7.778368749644854 15.440059717986403, 15.290446737554486 6.798402528114792, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C9.557007825434983 19.49098186417192, 19.109181713196193 8.50246280340994, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C8.269400297414974 20.97220488530608, 16.533966657156174 11.46490884567826, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C12.381592583292894 22.33868114203743, 25.019808052973467 7.800077342065066, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C10.375073706732453 24.646917066125155, 21.006770299852583 12.416549190240513, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C12.866313075108254 27.878086348743665, 25.594646831675124 13.235813318624427, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C9.116221042623618 32.19207374708522, 18.094462766705853 21.863788115307525, 36.877284942009794 0.25662288638767805 M1.1886405524609494 47.40872423549325 C16.041378277651415 30.322603995694497, 30.89411600284188 13.23648375589574, 42.520359378862906 -0.13797931854138312 M1.1886405524609494 47.40872423549325 C10.575569958155524 36.61029720636832, 19.9624993638501 25.811870177243396, 42.520359378862906 -0.13797931854138312 M6.831714989314069 47.014122030564195 C21.993421283387114 29.57257411029863, 37.15512757746016 12.131026190033062, 47.50737478672552 0.22212805675232872 M6.831714989314069 47.014122030564195 C19.326236998072215 32.64081864836124, 31.82075900683036 18.26751526615828, 47.50737478672552 0.22212805675232872 M11.818730397176676 47.3742294058579 C20.41523953522264 37.485076881063115, 29.0117486732686 27.59592435626833, 53.15044922357863 -0.1724741481767289 M11.818730397176676 47.3742294058579 C24.005080671428516 33.3554370510295, 36.19143094568036 19.33664469620109, 53.15044922357863 -0.1724741481767289 M17.461804834029795 46.979627200928846 C27.30168755303564 35.66013699022456, 37.141570272041484 24.340646779520274, 58.13746463144125 0.1876332271169865 M17.461804834029795 46.979627200928846 C29.966561935749773 32.59454969113763, 42.471319037469755 18.20947218134641, 58.13746463144125 0.1876332271169865 M22.448820241892403 47.33973457622256 C34.096683995671754 33.94040010226008, 45.7445477494511 20.5410656282976, 63.78053906829436 -0.20696897781207468 M22.448820241892403 47.33973457622256 C34.61132520278209 33.34837311654626, 46.77383016367178 19.35701165686996, 63.78053906829436 -0.20696897781207468 M28.091894678745525 46.9451323712935 C37.873037623192126 35.69321454148944, 47.65418056763873 24.44129671168539, 68.76755447615697 0.1531383974816336 M28.091894678745525 46.9451323712935 C42.805641640247245 30.01890271493779, 57.51938860174897 13.092673058582086, 68.76755447615697 0.1531383974816336 M33.07891008660813 47.30523974658722 C41.52728154943033 37.58650012328902, 49.97565301225252 27.867760499990823, 73.09851085502908 1.2679553529981291 M33.07891008660813 47.30523974658722 C45.01406722213595 33.57541204265762, 56.949224357663766 19.84558433872802, 73.09851085502908 1.2679553529981291 M38.72198452346125 46.91063754165816 C50.628924475497925 33.21326999415753, 62.53586442753459 19.5159024466569, 73.49311305995813 6.911029789851241 M38.72198452346125 46.91063754165816 C49.1254441827442 34.94282622382081, 59.52890384202714 22.97501490598346, 73.49311305995813 6.911029789851241 M43.70899993132386 47.27074491695187 C52.9683870680543 36.61903848462857, 62.22777420478474 25.967332052305267, 73.23165623589668 13.30881380692713 M43.70899993132386 47.27074491695187 C52.332436774433255 37.35061561097314, 60.95587361754265 27.430486304994417, 73.23165623589668 13.30881380692713 M49.35207436817697 46.87614271202281 C54.29645130424312 41.188287691380104, 59.24082824030926 35.500432670737396, 72.97019941183524 19.706597824003016 M49.35207436817697 46.87614271202281 C55.52636925090044 39.77342894207139, 61.7006641336239 32.67071517211997, 72.97019941183524 19.706597824003016 M54.339089776039586 47.23625008731652 C61.848158492637964 38.59805466809013, 69.35722720923634 29.95985924886374, 73.3648016167643 25.34967226085613 M54.339089776039586 47.23625008731652 C61.44910340704825 39.05711503129342, 68.55911703805691 30.877979975270318, 73.3648016167643 25.34967226085613 M59.9821642128927 46.84164788238747 C65.10228084440658 40.95162746820704, 70.22239747592046 35.061607054026624, 73.10334479270284 31.747456277932027 M59.9821642128927 46.84164788238747 C63.95140054181702 42.27556380879902, 67.92063687074135 37.70947973521058, 73.10334479270284 31.747456277932027 M64.96917962075531 47.20175525768118 C67.92874239103999 43.7971677475582, 70.88830516132467 40.39258023743522, 73.49794699763191 37.39053071478514 M64.96917962075531 47.20175525768118 C67.98336749725237 43.734328751130384, 70.99755537374942 40.2669022445796, 73.49794699763191 37.39053071478514 M69.95619502861793 47.561862632974886 C71.01105223518607 46.34838822840949, 72.0659094417542 45.134913823844094, 73.23649017357046 43.78831473186103 M69.95619502861793 47.561862632974886 C71.2324011335524 46.093755448755694, 72.50860723848686 44.625648264536494, 73.23649017357046 43.78831473186103" stroke="#4c6ef5" stroke-width="0.5" fill="none"></path><path d="M0 0 C23.49195336699486 0, 46.98390673398972 0, 72 0 M0 0 C20.274025350809097 0, 40.548050701618195 0, 72 0 M72 0 C72 16.314749504625798, 72 32.629499009251596, 72 46 M72 0 C72 17.762838457524776, 72 35.52567691504955, 72 46 M72 46 C46.1160380423069 46, 20.232076084613794 46, 0 46 M72 46 C43.98897323012352 46, 15.97794646024704 46, 0 46 M0 46 C0 36.70909492820501, 0 27.418189856410027, 0 0 M0 46 C0 28.832874299585818, 0 11.665748599171636, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1956.8630286524176 2765.9664198203873) rotate(0 40 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">incoming</text></g><g transform="translate(2143.3523444624875 2767.0952897232573) rotate(0 5.5 11.5)"><text x="5.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">3</text></g><g transform="translate(1956.8630286524176 2816.9664198203873) rotate(0 42 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">notify lost</text></g><g transform="translate(2143.3523444624875 2824.0952897232573) rotate(0 5.5 11.5)"><text x="5.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">1</text></g><g transform="translate(1956.8630286524176 2880.9664198203873) rotate(0 53.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">after update</text></g><g transform="translate(2143.8523444624875 2882.0952897232573) rotate(0 11 11.5)"><text x="11" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">17</text></g><g transform="translate(2109.3576865574523 2756.0308547718223) rotate(0 52.5 20.5)"><path d="M0 0 C31.698343444615606 0, 63.39668688923121 0, 105 0 M0 0 C31.209965955466036 0, 62.41993191093207 0, 105 0 M105 0 C105 11.741622019559145, 105 23.48324403911829, 105 41 M105 0 C105 9.947629534453155, 105 19.89525906890631, 105 41 M105 41 C79.51778180524707 41, 54.03556361049414 41, 0 41 M105 41 C71.71336268261075 41, 38.4267253652215 41, 0 41 M0 41 C0 31.30118932649493, 0 21.602378652989863, 0 0 M0 41 C0 28.524867499619724, 0 16.049734999239444, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2110.3576865574523 2813.0308547718223) rotate(0 51 22.5)"><path d="M0 0 C28.886803181469443 0, 57.773606362938885 0, 102 0 M0 0 C37.173303835093975 0, 74.34660767018795 0, 102 0 M102 0 C102 13.430311616510155, 102 26.86062323302031, 102 45 M102 0 C102 16.05211198702455, 102 32.1042239740491, 102 45 M102 45 C62.9927919074893 45, 23.985583814978597 45, 0 45 M102 45 C75.50919366627932 45, 49.01838733255863 45, 0 45 M0 45 C0 35.4621723331511, 0 25.924344666302204, 0 0 M0 45 C0 31.916056986898184, 0 18.832113973796368, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2331.979606674974 2957.8188617836304) rotate(0 21.5 11.5)"><text x="21.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">clear</text></g><g transform="translate(2415.162496303048 2947.242131981392) rotate(0 36 23)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.4970441935106777 4.374860002394918, 3.255545211082804 2.3519359877139463, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.0193498443811764 4.924384489941499, 2.300156512823801 3.450984962807109, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C3.695068028794355 7.943335170789077, 7.256990676721099 3.8458118876491483, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C3.2546144924552527 8.450019003842351, 6.376083604042894 4.8591795537556965, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C6.041150369986185 11.341488511566151, 12.210612183166209 4.244334552127405, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C5.344291267072877 12.143133207841995, 10.816893977339593 5.847623944679093, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C8.414446457345543 14.708336018509971, 16.56260215295586 5.33495512916193, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C6.4214844934095785 17.000976498615042, 12.576678225083935 9.92023608937207, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C6.6772876169141355 22.8037210136902, 13.349741296154498 15.127941102446501, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C6.9544811298598415 22.484846353710854, 13.90412832204591 14.490191782487804, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C6.872640764250068 28.676005271567007, 14.001904414887814 20.474725601124224, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C10.997917141478736 23.93041765614801, 22.25245716934515 10.983550370286228, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C11.256541242895041 29.72991700735603, 22.3751031672487 16.939474635849148, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C11.845267458656053 29.05266496824178, 23.552555598770724 15.58497055762065, 36.877284942009794 0.25662288638767805 M1.1886405524609494 47.40872423549325 C16.24604414541426 30.08716284738364, 31.303447738367574 12.76560145927403, 42.520359378862906 -0.13797931854138312 M1.1886405524609494 47.40872423549325 C15.538740655247599 30.900822436788527, 29.88884075803425 14.392920638083801, 42.520359378862906 -0.13797931854138312 M6.831714989314069 47.014122030564195 C15.158556348394061 37.43518679913732, 23.485397707474053 27.85625156771044, 47.50737478672552 0.22212805675232872 M6.831714989314069 47.014122030564195 C20.84115003976956 30.898110545505528, 34.85058509022505 14.78209906044686, 47.50737478672552 0.22212805675232872 M11.818730397176676 47.3742294058579 C21.211286517846283 36.56932958158926, 30.60384263851589 25.76442975732062, 53.15044922357863 -0.1724741481767289 M11.818730397176676 47.3742294058579 C23.229577828526097 34.24755102121452, 34.640425259875514 21.120872636571143, 53.15044922357863 -0.1724741481767289 M17.461804834029795 46.979627200928846 C30.306104344153184 32.20395083159861, 43.150403854276576 17.42827446226838, 58.13746463144125 0.1876332271169865 M17.461804834029795 46.979627200928846 C29.255969708044375 33.41199254030672, 41.05013458205896 19.84435787968459, 58.13746463144125 0.1876332271169865 M22.448820241892403 47.33973457622256 C35.24597035382438 32.6182973849912, 48.04312046575637 17.896860193759842, 63.78053906829436 -0.20696897781207468 M22.448820241892403 47.33973457622256 C32.40388163119093 35.88774646202785, 42.35894302048945 24.435758347833136, 63.78053906829436 -0.20696897781207468 M28.091894678745525 46.9451323712935 C39.423679421275665 33.90940520605776, 50.7554641638058 20.873678040822032, 68.76755447615697 0.1531383974816336 M28.091894678745525 46.9451323712935 C36.86256421475625 36.85563122689101, 45.63323375076697 26.766130082488527, 68.76755447615697 0.1531383974816336 M33.07891008660813 47.30523974658722 C49.00458898942211 28.98484187324387, 64.93026789223609 10.66444399990052, 73.09851085502908 1.2679553529981291 M33.07891008660813 47.30523974658722 C43.409127522921416 35.42168396812881, 53.7393449592347 23.5381281896704, 73.09851085502908 1.2679553529981291 M38.72198452346125 46.91063754165816 C46.490976769857184 37.97343430545929, 54.25996901625312 29.036231069260428, 73.49311305995813 6.911029789851241 M38.72198452346125 46.91063754165816 C48.95423324235933 35.13978188061016, 59.186481961257414 23.36892621956216, 73.49311305995813 6.911029789851241 M43.70899993132386 47.27074491695187 C54.52169625510804 34.8321606691958, 65.33439257889222 22.39357642143973, 73.23165623589668 13.30881380692713 M43.70899993132386 47.27074491695187 C51.29617725229622 38.54269582692153, 58.88335457326858 29.814646736891184, 73.23165623589668 13.30881380692713 M49.35207436817697 46.87614271202281 C58.04537107987899 36.87564882028253, 66.73866779158101 26.87515492854224, 72.97019941183524 19.706597824003016 M49.35207436817697 46.87614271202281 C54.34157254094606 41.13638164618229, 59.33107071371516 35.396620580341775, 72.97019941183524 19.706597824003016 M54.339089776039586 47.23625008731652 C61.493812828987195 39.005682724789736, 68.6485358819348 30.775115362262955, 73.3648016167643 25.34967226085613 M54.339089776039586 47.23625008731652 C59.64835957910307 41.12863384045977, 64.95762938216656 35.02101759360303, 73.3648016167643 25.34967226085613 M59.9821642128927 46.84164788238747 C62.83992437265473 43.554170879182365, 65.69768453241676 40.26669387597726, 73.10334479270284 31.747456277932027 M59.9821642128927 46.84164788238747 C64.76384713880717 41.34095091106735, 69.54553006472162 35.84025393974723, 73.10334479270284 31.747456277932027 M64.96917962075531 47.20175525768118 C67.32639823571641 44.490085434116665, 69.68361685067751 41.77841561055215, 73.49794699763191 37.39053071478514 M64.96917962075531 47.20175525768118 C67.3437430886772 44.47013246324269, 69.71830655659907 41.7385096688042, 73.49794699763191 37.39053071478514 M69.95619502861793 47.561862632974886 C71.15470381114815 46.183135993775196, 72.35321259367839 44.8044093545755, 73.23649017357046 43.78831473186103 M69.95619502861793 47.561862632974886 C70.82261474171672 46.56516076763254, 71.68903445481551 45.5684589022902, 73.23649017357046 43.78831473186103" stroke="#4c6ef5" stroke-width="0.5" fill="none"></path><path d="M0 0 C26.955635350942615 0, 53.91127070188523 0, 72 0 M0 0 C26.84984226822853 0, 53.69968453645706 0, 72 0 M72 0 C72 16.324836088716985, 72 32.64967217743397, 72 46 M72 0 C72 16.064654491841793, 72 32.129308983683586, 72 46 M72 46 C47.6831055700779 46, 23.36621114015579 46, 0 46 M72 46 C47.87400836348533 46, 23.74801672697067 46, 0 46 M0 46 C0 28.00655534118414, 0 10.013110682368279, 0 0 M0 46 C0 30.18186087757349, 0 14.36372175514698, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2423.662496303048 2957.742131981392) rotate(0 25 11.5)"><text x="25" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">never</text></g><g transform="translate(2096.0885167112115 2951.7716658736545) rotate(0 71.39795918367349 18.459183673469397)"><path d="M-1.39677394926548 0.32469500601291656 L144.1485536168425 1.0561283975839615 L143.16979814275192 36.469005918320306 L0.8744791597127914 36.901885843094476" stroke="none" stroke-width="0" fill="#fff"></path><path d="M1.97709359228611 0.2847932428121567 C45.81741551317428 -1.4418476016348118, 94.41446656003902 -1.710245409709763, 144.25420788629935 1.0933693498373032 M0.36778729408979416 -0.539526991546154 C29.279434256453307 -1.328064804577402, 57.55820005426604 -0.7314215951200045, 143.34479577793763 0.8614866212010384 M142.79116085871146 -1.6496993452310562 C142.0197555263934 12.957873272211563, 143.791121168941 28.65417574805262, 143.7805507551043 38.108356779631265 M143.4031320358722 0.810993380844593 C142.26080883488825 14.157132057313394, 143.62355817303828 30.160688031145476, 143.17326481594728 37.808787731643804 M142.3686511884539 36.304374998625406 C109.32375555161619 36.44563753010511, 71.09515935325503 34.99013645054578, 0.7016643434762955 34.95789129119743 M142.0741914059131 36.43621197175611 C86.5527700301488 35.87242209359239, 29.673369833583735 36.724482173166976, 0.9116184040904045 37.65035119485486 M0.7120059877634048 38.15940267425407 C-1.6189305448547313 27.43336544385063, 0.17987040042725105 15.783362759345628, 0.8774517923593521 -0.5245310217142105 M-0.6241615489125252 36.01623979043592 C-0.7518961163610218 25.33034535988554, -0.20926091395318497 13.12852838294845, -0.6112461760640144 0.5358352139592171" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2130.7364758948847 2958.2308495471234) rotate(0 5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(2161.2364758948847 2957.7308495471234) rotate(0 5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(2250.2364758948847 2950.7308495471234) rotate(0 17.75 17.75)"><path d="M1.0561283975839615 0.3738797754049301 L35.05063857138157 0.8744791597127914 L35.48351849615574 35.92132793366909 L1.9206861406564713 36.94069562852383" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-0.055244579911231995 1.2888831049203873 C13.835698738321664 1.590593797005713, 29.412051602452998 -1.8358097254857422, 36.66893516480923 1.669340506196022 M-0.1361897513270378 -0.015486307442188263 C12.416098352149131 0.3740075787529349, 24.77277640923858 0.6458221634849906, 35.12330622226 0.6146547123789787 M34.35250221192837 1.1342719942331314 C35.65061199370771 11.626187809929252, 36.39716779891401 23.263016345351936, 35.518439158797264 33.57663430273533 M34.9268779233098 0.824236087501049 C36.48808241333813 13.18295497186482, 36.6783230349049 25.09360714480281, 35.95243377238512 34.930626802146435 M35.840311869978905 34.69427575170994 C24.49321003295481 36.55228977914899, 13.756322429329153 37.71093874689191, -0.8161541372537613 34.9236406236887 M34.865563578903675 34.619517259299755 C27.62975437156856 36.36826742265374, 20.056245274096728 35.048971777893605, -0.9880843684077263 35.67945259064436 M0.08543048799037933 35.31508578360081 C-2.2144235760346054 24.463641164079306, -0.7448147923126817 12.03542957678437, 0.8267763704061508 1.3221758753061295 M0.1576504185795784 35.44335525482893 C0.021761129833757886 26.45452732257545, 0.8560904965177178 17.933160022646188, 0.16234750300645828 0.6763176247477531" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2251.2364758948847 2951.7308495471234) rotate(0 17.5 4.5)"><path d="M0.3738797754049301 -0.4493614286184311 L35.87447915971279 -0.01648150384426117 L35.42132793366909 10.920686140656471 L1.4406956285238266 8.818684473633766" stroke="none" stroke-width="0" fill="#000"></path><path d="M1.2888831049203873 -0.32364238798618317 C12.456677693873644 1.1030371513217687, 20.028662346303463 1.1786029662936925, 36.66934050619602 0.7355745881795883 M-0.015486307442188263 0.46045345813035965 C9.16053294017911 0.9091530341655016, 18.044003054499626 -0.32902736477553846, 35.61465471237898 -0.0023787543177604675 M35.51042239740491 0.199545132368803 C35.41441536031663 2.4931305393576624, 35.86228826127947 3.923568210750818, 34.1344854362309 9.546492301672696 M35.37090623937547 0.3150808934122324 C35.12133970931173 3.830583215877414, 34.71860935166478 7.0633832830935726, 34.7437820609659 8.903864884749055 M34.19427575170994 7.8848107904195786 C26.276150953024626 7.099078521504998, 18.009286530315876 8.243400439992547, -0.5763593763113022 7.556546077132225 M34.119517259299755 9.21762365847826 C27.099162217229605 9.509931100532413, 16.967410385608673 7.78986288420856, 0.1794525906443596 9.356002993881702 M-0.08321139737963679 8.10263708755374 C0.48412048883736136 5.505495142936707, 0.25264005728065975 2.8551175720989703, 0.5949791438877582 -0.5617453940212727 M-0.025490135326981522 8.865677631273865 C-0.22112558394670487 7.3530406471341845, -0.2603389433026314 5.29688597805798, 0.30434293113648897 0.23762888945639132" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2258.7364758948847 2943.2308495471234) rotate(0 3 7)"><path d="M-0.4493614286184311 0.8744791597127914 L5.983518496155739 0.42132793366909027 L7.920686140656471 15.440695628523827 L-0.18131552636623383 13.718226775527" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-0.09709271639585493 0.4374868556857109 C1.9043979406356812 -0.6291006942093372, 3.503454820811749 0.4621356587111949, 6.2206723764538765 -0.3237161949276924 M0.1381360374391079 0.16466322317719456 C2.354000631719828 0.24713677704334253, 4.0781011573970325 0.18532559216022487, 5.999286373704672 -0.24745490178465843 M6.31040353924036 0.6892426714301108 C6.752667757719754 5.13996829688549, 5.93258256599307 6.161712904274465, 6.850099135935306 15.13539073318243 M6.490125834196806 0.2641425140202045 C6.54305717855692 3.0837545178830625, 6.236466549932957 6.493601659685374, 5.850456487387419 13.785102678090334 M5.665443237125873 14.210499303042889 C3.019250813126564 14.533922265917063, 0.9699410185217858 13.802920459657908, -0.43303617686033247 13.710706774890422 M6.065287097543478 14.273485521227121 C4.492864418774843 13.824867863357067, 2.2501132182776926 14.001006812751294, 0.10680089816451072 14.1861552990973 M-1.395897863805294 14.614216254651547 C-0.3731518493592739 11.442736196517943, 0.572763325124979 9.302724339067936, -0.8738261684775352 -1.2629785791039465 M-0.20894590690732 13.57212767675519 C0.35301359117031095 10.150121044367552, 0.09157219350337978 7.751406190544366, 0.36964493915438656 0.13085792139172558" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2273.7364758948847 2943.2308495471234) rotate(0 3 7)"><path d="M0.8744791597127914 -0.01648150384426117 L6.42132793366909 1.9206861406564713 L7.440695628523827 13.818684473633766 L-0.2817732244729996 12.524681463837624" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0.4374868556857109 0.32801080495119095 C1.1929924249649049 0.36038982108235357, 4.067655403912068 0.23038164809346198, 5.676283805072307 0.29555464535951614 M0.16466322317719456 0.2584459863603115 C1.9644937478005886 -0.14063534080982207, 3.620968712121248 -0.028340833783149694, 5.752545098215341 -0.09556404724717141 M6.689242671430111 0.8329926028847692 C7.4653328903019425 3.4096589595079427, 4.73304305151105 7.643602232635022, 7.13539073318243 13.246081449091434 M6.264142514020205 0.6232942692935466 C5.753066121041774 3.7143327333033085, 5.716831813752651 6.645714672654868, 5.785102678090334 14.69137409850955 M6.210499303042889 13.411857183277608 C4.6560004323720925 13.72169808253646, 2.022905065119266 13.533508146852256, -0.28929322510957717 13.926730735599994 M6.273485521227121 14.219595154374838 C4.458358680456877 13.716632108986378, 3.2151594825088976 14.119858317673208, 0.18615529909729955 13.702442725747824 M0.6142162546515464 13.632828284800052 C0.26707957848906516 10.318942117691039, 0.938467107862234 4.606571148335933, -1.2629785791039465 -0.8389919266104697 M-0.42787232324481006 14.375084649771452 C-0.48094061791896814 9.69293266609311, 0.48135260164737703 5.528223767131567, 0.13085792139172558 -0.15727650001645088" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(2267.2364758948847 2959.7308495471234) rotate(0 0.8333176635205746 12.12975324690342)"><path d="M1.0933693498373032 -1.9681140035390854 C1.3082746260240674 11.323464896418153, 1.0571361270174384 18.23284052114934, 1.4851821511983871 26.227620497345924 M0.8614866212010384 0.8206919953227043 C-0.10544792670756575 8.520871610604228, 0.41809278134256606 14.990328510887922, 0.181453175842762 25.926251105964184" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(2257.7364758948847 2958.7308495471234) rotate(0 -0.5737110041081905 14.095221109688282)"><path d="M-1.9681140035390854 1.168935164809227 C2.015409979149699 8.67974182162434, -0.5910755698382855 16.876250041462484, 0.22762049734592438 27.969027385115623 M0.8206919953227043 -0.3766937777400017 C0.9413630602508783 9.682583495341241, -0.3251186518371105 19.05568510826677, -0.07374889403581619 28.567135997116566" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(2277.236475894885 2960.2308495471234) rotate(0 0.845221109688282 13.517780814319849)"><path d="M1.168935164809227 1.669340506196022 C1.4343508942052723 8.445026008598507, 2.243330171145499 18.761019625701014, 1.4690273851156235 26.42090691626072 M-0.3766937777400017 0.6146547123789787 C0.7496319456771017 8.212477344460787, 0.9657954874262213 17.513215520046653, 2.0671359971165657 25.721716813743114" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(2286.2364758948847 2968.2308495471234) rotate(0 -16.05447134003043 0.48556103962073394)"><path d="M1.669340506196022 0.7355745881795883 C-13.137781877815724 1.1839011292159558, -24.38983529210091 0.16774636313319208, -33.07909308373928 1.0977548211812973 M0.6146547123789787 -0.0023787543177604675 C-13.95390418469906 -0.44662270858883857, -26.83185791820288 0.43906011268496514, -33.778283186256886 0.49231619387865067" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(2285.7364758948847 2977.2308495471234) rotate(0 -17.38605460897088 0.8219596296548843)"><path d="M0.7355745881795883 -1.079053983092308 C-6.266367966607214 0.22969608828425414, -14.539917526319625 1.6245768070220947, -34.9022451788187 2.7229732424020767 M-0.0023787543177604675 -0.8248496726155281 C-14.076804945096374 0.029596001952886586, -26.945613306984306 1.2071309092640878, -35.50768380612135 1.5949947163462639" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(1824.15996631772 1770.2890595675917) rotate(0 244 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"># updating product: initial state</text></g><g transform="translate(1855.6599663177199 2520.2890595675917) rotate(0 275 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"># updating product: updating stock</text></g><g transform="translate(1230.1599663177199 1685.2890595675917) rotate(0 98 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">alternative 1</text></g><g transform="translate(2047.6599663177199 1692.7890595675917) rotate(0 98 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">alternative 2</text></g><g transform="translate(1410.3187679866014 1348.8928867907737) rotate(0 42.85000000000002 19.5)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.4245540883265806 4.458250329234831, 3.1105650007146095 2.5187166413937736, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.0416068012916408 4.8987807898708216, 2.34467042664473 3.399777562665754, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C3.2858567810230084 8.414078862104724, 6.438568181178406 4.78729927028044, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C2.2853176939057724 9.56506741811414, 4.437490006943934 7.089276382299275, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C4.912805019729161 12.639501354936556, 9.953921482652161 6.840360238868213, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C3.6729466808315223 14.06579521743392, 7.474204804856884 9.69294796386294, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C7.506626709289865 15.75266317612456, 14.746962656844508 7.423609444391108, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C7.989401072722355 15.19729480061559, 15.712511383709488 6.312872693373166, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C7.108748000762871 22.307382619143166, 14.212662063851969 14.13526431335243, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C5.260777704715555 24.433229265198854, 10.516721471757338 18.386957605463806, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C7.808664564618157 27.599233063216616, 15.873952015623992 18.321181184423438, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C7.298340080009983 28.1862942277412, 14.853303046407644 19.49530351347261, 31.89026953414718 -0.10348448890603734 M2.1061564055129054 40.256230638194594 C9.780493364357602 31.427915854371093, 17.454830323202298 22.599601070547592, 36.877284942009794 0.25662288638767805 M2.1061564055129054 40.256230638194594 C13.368263852888148 27.300658032005664, 24.63037130026339 14.345085425816738, 36.877284942009794 0.25662288638767805 M7.093171813375516 40.6163380134883 C14.974944290744936 31.549395962618448, 22.85671676811436 22.482453911748596, 42.520359378862906 -0.13797931854138312 M7.093171813375516 40.6163380134883 C19.465076460800553 26.384089769939752, 31.836981108225594 12.151841526391202, 42.520359378862906 -0.13797931854138312 M12.736246250228632 40.221735808559245 C24.22926903898746 27.000525488899985, 35.72229182774629 13.779315169240725, 47.50737478672552 0.22212805675232872 M12.736246250228632 40.221735808559245 C23.12470329438591 28.27118302518816, 33.51316033854319 16.320630241817078, 47.50737478672552 0.22212805675232872 M17.723261658091243 40.58184318385296 C31.052683527570583 25.24809737868312, 44.382105397049926 9.914351573513276, 53.15044922357863 -0.1724741481767289 M17.723261658091243 40.58184318385296 C29.795719308109998 26.694069305757793, 41.86817695812876 12.806295427662622, 53.15044922357863 -0.1724741481767289 M22.710277065953854 40.941950559146676 C32.38282151190626 29.81496101108199, 42.055365957858655 18.687971463017305, 58.13746463144125 0.1876332271169865 M22.710277065953854 40.941950559146676 C33.30055899329363 28.75922480637138, 43.890840920633394 16.576499053596084, 58.13746463144125 0.1876332271169865 M28.353351502806966 40.54734835421761 C40.44468713249262 26.63785784472148, 52.53602276217828 12.728367335225354, 63.78053906829436 -0.20696897781207468 M28.353351502806966 40.54734835421761 C39.953269725938405 27.203168903979936, 51.55318794906984 13.858989453742264, 63.78053906829436 -0.20696897781207468 M33.34036691066958 40.90745572951133 C41.61400376214182 31.389725282758157, 49.88764061361407 21.871994836004983, 68.76755447615697 0.1531383974816336 M33.34036691066958 40.90745572951133 C47.01201809050106 25.18002013768735, 60.68366927033254 9.452584545863374, 68.76755447615697 0.1531383974816336 M38.98344134752269 40.51285352458227 C48.167500219764634 29.947802347897323, 57.35155909200658 19.38275117121238, 74.41062891301009 -0.2414638074474169 M38.98344134752269 40.51285352458227 C50.12455077371315 27.696473219300575, 61.26566019990361 14.880092914018881, 74.41062891301009 -0.2414638074474169 M43.97045675538531 40.872960899875984 C54.950211905547526 28.242197456107192, 65.92996705570975 15.6114340123384, 79.3976443208727 0.11864356784629138 M43.97045675538531 40.872960899875984 C54.90763642626359 28.291174942397724, 65.84481609714189 15.70938898491946, 79.3976443208727 0.11864356784629138 M49.613531192238426 40.47835869494692 C63.22322650475755 24.82219517552106, 76.83292181727667 9.166031656095196, 85.04071875772581 -0.27595863708276624 M49.613531192238426 40.47835869494692 C63.59626442284176 24.393064139861472, 77.5789976534451 8.307769584776025, 85.04071875772581 -0.27595863708276624 M54.60054660010103 40.838466070240635 C65.05761358779769 28.80898657540063, 75.51468057549434 16.779507080560627, 88.0595570786169 2.348277478879261 M54.60054660010103 40.838466070240635 C64.76865042983721 29.141400663169186, 74.93675425957338 17.444335256097734, 88.0595570786169 2.348277478879261 M60.24362103695415 40.44386386531157 C68.21785733748133 31.27055435347016, 76.19209363800852 22.097244841628747, 88.45415928354596 7.991351915732373 M60.24362103695415 40.44386386531157 C70.07031189293934 29.139549157058624, 79.89700274892454 17.83523444880568, 88.45415928354596 7.991351915732373 M65.23063644481675 40.80397124060529 C73.59383619649051 31.183210463001203, 81.95703594816428 21.562449685397112, 88.19270245948451 14.389135932808273 M65.23063644481675 40.80397124060529 C72.01490616069215 32.99956169339599, 78.79917587656755 25.19515214618668, 88.19270245948451 14.389135932808273 M70.87371088166988 40.40936903567623 C74.86289472535546 35.82033797130387, 78.85207856904103 31.231306906931508, 87.93124563542307 20.786919949884158 M70.87371088166988 40.40936903567623 C75.0218753433517 35.637451691000514, 79.17003980503353 30.865534346324804, 87.93124563542307 20.786919949884158 M75.8607262895325 40.76947641096994 C79.60436868969872 36.46290846588569, 83.34801108986494 32.156340520801436, 88.32584784035213 26.429994386737274 M75.8607262895325 40.76947641096994 C79.53695074376839 36.54046394096367, 83.21317519800428 32.3114514709574, 88.32584784035213 26.429994386737274 M81.5038007263856 40.374874206040886 C83.00849972587095 38.64391601465589, 84.51319872535629 36.9129578232709, 88.06439101629068 32.82777840381317 M81.5038007263856 40.374874206040886 C83.04239395530837 38.60492516392397, 84.58098718423113 36.83497612180707, 88.06439101629068 32.82777840381317" stroke="#fa5252" stroke-width="0.5" fill="none"></path><path d="M0 0 C32.74580490000551 0, 65.49160980001102 0, 85.70000000000013 0 M0 0 C19.455593113824758 0, 38.911186227649516 0, 85.70000000000013 0 M85.70000000000013 0 C85.70000000000013 13.62363718673587, 85.70000000000013 27.24727437347174, 85.70000000000013 39 M85.70000000000013 0 C85.70000000000013 7.82143609598279, 85.70000000000013 15.64287219196558, 85.70000000000013 39 M85.70000000000013 39 C56.40713170640179 39, 27.114263412803453 39, 0 39 M85.70000000000013 39 C63.53586610801528 39, 41.37173221603042 39, 0 39 M0 39 C0 25.79555174186826, 0 12.591103483736518, 0 0 M0 39 C0 26.93629071637988, 0 14.872581432759759, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1425.6641836672989 840.473507170834) rotate(0 21.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">clear</text></g><g transform="translate(1406.5687679866014 833.2238730819438) rotate(0 42.85000000000002 19.5)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.4555318372155774 4.422614505586104, 3.172520498492603 2.447444994096318, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.1870386413074132 4.7314805957126564, 2.6355341066762747 3.0651771743494245, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C2.762329949078644 9.016327589906023, 5.391514517289677 5.991796725883039, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C2.8222380466076165 8.947411207171978, 5.511330712347622 5.853963960414949, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C6.064106454627717 11.315080557041043, 12.256524352449272 4.1915186430771865, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C3.24002755519765 14.56381170244487, 6.608366553589139 10.68898093388484, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C7.425263986294751 15.846260282183612, 14.58423721085428 7.610803656509212, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C5.943864090256802 17.55041592104616, 11.621437418778381 11.019114934234302, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C7.471353066344916 21.89025320739928, 14.937872195016059 13.301005489864657, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C5.357450122959003 24.322020369401937, 10.710066308244233 18.164539813869972, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C9.23323120088127 25.960456610878424, 18.72308528815022 15.043628279747054, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C11.791742976225766 23.01722549501918, 23.84010883883921 9.157166048028564, 31.89026953414718 -0.10348448890603734 M2.1061564055129054 40.256230638194594 C16.01034648426053 24.261289643607526, 29.914536563008152 8.266348649020458, 36.877284942009794 0.25662288638767805 M2.1061564055129054 40.256230638194594 C10.806458292634769 30.24767821396427, 19.506760179756633 20.23912578973395, 36.877284942009794 0.25662288638767805 M7.093171813375516 40.6163380134883 C16.157048766897635 30.189540319217848, 25.220925720419753 19.76274262494739, 42.520359378862906 -0.13797931854138312 M7.093171813375516 40.6163380134883 C18.769447291424736 27.18431958953109, 30.445722769473957 13.752301165573876, 42.520359378862906 -0.13797931854138312 M12.736246250228632 40.221735808559245 C20.590166252526892 31.18683436507417, 28.44408625482515 22.15193292158909, 47.50737478672552 0.22212805675232872 M12.736246250228632 40.221735808559245 C22.099060073144468 29.451050583984703, 31.461873896060304 18.680365359410164, 47.50737478672552 0.22212805675232872 M17.723261658091243 40.58184318385296 C26.69354294820576 30.2627149838195, 35.663824238320274 19.943586783786042, 53.15044922357863 -0.1724741481767289 M17.723261658091243 40.58184318385296 C25.080546201339722 32.118255482364454, 32.4378307445882 23.65466778087595, 53.15044922357863 -0.1724741481767289 M22.710277065953854 40.941950559146676 C34.63283553007527 27.226615968775953, 46.55539399419669 13.51128137840523, 58.13746463144125 0.1876332271169865 M22.710277065953854 40.941950559146676 C32.99233191221806 29.11379950269066, 43.274386758482265 17.285648446234642, 58.13746463144125 0.1876332271169865 M28.353351502806966 40.54734835421761 C35.61771520518492 32.19065385243897, 42.88207890756287 23.833959350660326, 63.78053906829436 -0.20696897781207468 M28.353351502806966 40.54734835421761 C42.3260917323811 24.47354943180949, 56.29883196195524 8.399750509401372, 63.78053906829436 -0.20696897781207468 M33.34036691066958 40.90745572951133 C47.27698140814668 24.87521470799536, 61.213595905623784 8.842973686479397, 68.76755447615697 0.1531383974816336 M33.34036691066958 40.90745572951133 C42.363685514622375 30.527315079234448, 51.38700411857516 20.14717442895757, 68.76755447615697 0.1531383974816336 M38.98344134752269 40.51285352458227 C50.201826110359974 27.607578113364703, 61.42021087319726 14.702302702147133, 74.41062891301009 -0.2414638074474169 M38.98344134752269 40.51285352458227 C52.71637700351996 24.714918207524086, 66.44931265951723 8.9169828904659, 74.41062891301009 -0.2414638074474169 M43.97045675538531 40.872960899875984 C56.20877578647401 26.794385329019903, 68.44709481756271 12.715809758163818, 79.3976443208727 0.11864356784629138 M43.97045675538531 40.872960899875984 C51.65038491822366 32.038214171619856, 59.330313081062 23.20346744336373, 79.3976443208727 0.11864356784629138 M49.613531192238426 40.47835869494692 C59.5617026089435 29.03429658755033, 69.50987402564857 17.59023448015374, 85.04071875772581 -0.27595863708276624 M49.613531192238426 40.47835869494692 C63.703566274137145 24.269627480094943, 77.79360135603586 8.060896265242967, 85.04071875772581 -0.27595863708276624 M54.60054660010103 40.838466070240635 C62.270941628361385 32.01468595882482, 69.94133665662174 23.190905847409006, 88.0595570786169 2.348277478879261 M54.60054660010103 40.838466070240635 C66.07942668606204 27.633525069072714, 77.55830677202303 14.428584067904794, 88.0595570786169 2.348277478879261 M60.24362103695415 40.44386386531157 C68.07941910245168 31.42980932539971, 75.91521716794921 22.41575478548785, 88.45415928354596 7.991351915732373 M60.24362103695415 40.44386386531157 C70.04673423488033 29.16667215000598, 79.8498474328065 17.889480434700385, 88.45415928354596 7.991351915732373 M65.23063644481675 40.80397124060529 C73.69913319971204 31.062080117120125, 82.1676299546073 21.320188993634957, 88.19270245948451 14.389135932808273 M65.23063644481675 40.80397124060529 C72.41038734454995 32.54461263383561, 79.59013824428314 24.28525402706593, 88.19270245948451 14.389135932808273 M70.87371088166988 40.40936903567623 C77.2753954624955 33.04507334090056, 83.67708004332113 25.680777646124895, 87.93124563542307 20.786919949884158 M70.87371088166988 40.40936903567623 C75.51899407856129 35.06558200337773, 80.16427727545272 29.721794971079234, 87.93124563542307 20.786919949884158 M75.8607262895325 40.76947641096994 C80.54315134759022 35.38296255500032, 85.22557640564797 29.996448699030687, 88.32584784035213 26.429994386737274 M75.8607262895325 40.76947641096994 C79.81466061450901 36.22099527929023, 83.76859493948552 31.67251414761051, 88.32584784035213 26.429994386737274 M81.5038007263856 40.374874206040886 C83.66022725489519 37.89418925515019, 85.81665378340477 35.41350430425949, 88.06439101629068 32.82777840381317 M81.5038007263856 40.374874206040886 C83.60362085695817 37.95930746698352, 85.70344098753074 35.54374072792615, 88.06439101629068 32.82777840381317" stroke="#fa5252" stroke-width="0.5" fill="none"></path><path d="M0 0 C21.05272591106597 0, 42.10545182213194 0, 85.70000000000013 0 M0 0 C20.390299159362943 0, 40.780598318725886 0, 85.70000000000013 0 M85.70000000000013 0 C85.70000000000013 12.150230193883182, 85.70000000000013 24.300460387766364, 85.70000000000013 39 M85.70000000000013 0 C85.70000000000013 11.797666608542205, 85.70000000000013 23.59533321708441, 85.70000000000013 39 M85.70000000000013 39 C57.69139444358655 39, 29.682788887172975 39, 0 39 M85.70000000000013 39 C66.92966488234708 39, 48.15932976469404 39, 0 39 M0 39 C0 24.39182279035449, 0 9.783645580708978, 0 0 M0 39 C0 27.356765545159575, 0 15.713531090319155, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1415.6641836672989 260.31505805746497) rotate(0 21.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">clear</text></g><g transform="translate(1396.5687679866014 253.0654239685748) rotate(0 42.85000000000002 19.5)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.5247266891293827 4.343014934002126, 3.3109102023202137 2.2882458509283623, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C0.880941370554186 5.083605225523745, 2.0233395651698203 3.769426433971601, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C4.035985275130465 7.551154741127234, 7.938825169393319 3.061451028325461, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C2.67071835281382 9.121714675984162, 5.208291324760029 6.202570898039318, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C5.889131394208884 11.516366338598454, 11.906574231611607 4.594090206192011, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C5.443982487779084 12.028451577064278, 11.016276418752007 5.618260683123658, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C6.002808864492601 17.48260771499452, 11.73932696724998 10.883498522131026, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C7.539391620207313 15.714971457739715, 14.812492478679404 7.348226007621417, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C9.906993859538126 19.08836898757109, 19.80915378140248 7.69723705020828, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C6.400185529507074 23.12249050061828, 12.795537121340375 15.765480076302657, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C10.422681947823541 24.592150049650606, 21.10198678203476 12.307015157291417, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C7.042802353155541 28.480256755567623, 14.34222759269876 20.083228569125453, 31.89026953414718 -0.10348448890603734 M2.1061564055129054 40.256230638194594 C14.487790658574035 26.01278976370757, 26.869424911635164 11.769348889220545, 36.877284942009794 0.25662288638767805 M2.1061564055129054 40.256230638194594 C14.621202188054145 25.859317355034616, 27.136247970595385 11.462404071874637, 36.877284942009794 0.25662288638767805 M7.093171813375516 40.6163380134883 C18.525508948093822 27.464938553008803, 29.95784608281213 14.313539092529304, 42.520359378862906 -0.13797931854138312 M7.093171813375516 40.6163380134883 C18.172062686112294 27.87153196644271, 29.250953558849073 15.12672591939712, 42.520359378862906 -0.13797931854138312 M12.736246250228632 40.221735808559245 C20.949472545463763 30.773499757163894, 29.162698840698894 21.325263705768542, 47.50737478672552 0.22212805675232872 M12.736246250228632 40.221735808559245 C22.747549333443413 28.705049026514676, 32.75885241665819 17.188362244470106, 47.50737478672552 0.22212805675232872 M17.723261658091243 40.58184318385296 C28.57316026875329 28.100462600596217, 39.423058879415336 15.619082017339469, 53.15044922357863 -0.1724741481767289 M17.723261658091243 40.58184318385296 C29.94616841392979 26.52099740752805, 42.16907516976834 12.46015163120314, 53.15044922357863 -0.1724741481767289 M22.710277065953854 40.941950559146676 C30.60928203926329 31.855184789369865, 38.50828701257272 22.768419019593058, 58.13746463144125 0.1876332271169865 M22.710277065953854 40.941950559146676 C34.24309550344289 27.674960582443322, 45.77591394093193 14.407970605739969, 58.13746463144125 0.1876332271169865 M28.353351502806966 40.54734835421761 C36.5691095068009 31.09619990504985, 44.784867510794825 21.645051455882093, 63.78053906829436 -0.20696897781207468 M28.353351502806966 40.54734835421761 C41.74632990408641 25.140489122792403, 55.139308305365844 9.73362989136719, 63.78053906829436 -0.20696897781207468 M33.34036691066958 40.90745572951133 C40.74931779527038 32.384432701214415, 48.158268679871185 23.8614096729175, 68.76755447615697 0.1531383974816336 M33.34036691066958 40.90745572951133 C43.37070339550055 29.368873523565544, 53.401039880331524 17.83029131761976, 68.76755447615697 0.1531383974816336 M38.98344134752269 40.51285352458227 C50.89271684618298 26.81279923803224, 62.80199234484327 13.112744951482213, 74.41062891301009 -0.2414638074474169 M38.98344134752269 40.51285352458227 C52.38933444687543 25.09113763250474, 65.79522754622818 9.669421740427207, 74.41062891301009 -0.2414638074474169 M43.97045675538531 40.872960899875984 C57.25506820175456 25.59076358976619, 70.53967964812381 10.3085662796564, 79.3976443208727 0.11864356784629138 M43.97045675538531 40.872960899875984 C54.01549183903063 29.317469890223748, 64.06052692267596 17.761978880571508, 79.3976443208727 0.11864356784629138 M49.613531192238426 40.47835869494692 C61.766908843533585 26.49749700387109, 73.92028649482874 12.516635312795263, 85.04071875772581 -0.27595863708276624 M49.613531192238426 40.47835869494692 C57.59209042061002 31.300076223486606, 65.5706496489816 22.12179375202629, 85.04071875772581 -0.27595863708276624 M54.60054660010103 40.838466070240635 C67.59245085286398 25.892989868221868, 80.58435510562691 10.947513666203104, 88.0595570786169 2.348277478879261 M54.60054660010103 40.838466070240635 C66.71712723226744 26.899934507450432, 78.83370786443385 12.961402944660232, 88.0595570786169 2.348277478879261 M60.24362103695415 40.44386386531157 C67.69401400131045 31.873167177734402, 75.14440696566675 23.302470490157237, 88.45415928354596 7.991351915732373 M60.24362103695415 40.44386386531157 C68.99039340992344 30.381853262294154, 77.73716578289273 20.319842659276738, 88.45415928354596 7.991351915732373 M65.23063644481675 40.80397124060529 C69.92256920361453 35.40652002607902, 74.6145019624123 30.009068811552748, 88.19270245948451 14.389135932808273 M65.23063644481675 40.80397124060529 C71.3558200342678 33.75775355087222, 77.48100362371885 26.71153586113916, 88.19270245948451 14.389135932808273 M70.87371088166988 40.40936903567623 C77.66819664726737 32.59320726762002, 84.46268241286487 24.77704549956382, 87.93124563542307 20.786919949884158 M70.87371088166988 40.40936903567623 C76.62275497634309 33.79585033744366, 82.3717990710163 27.182331639211093, 87.93124563542307 20.786919949884158 M75.8607262895325 40.76947641096994 C79.17495020512054 36.95689792402115, 82.48917412070857 33.144319437072355, 88.32584784035213 26.429994386737274 M75.8607262895325 40.76947641096994 C79.07364264013388 37.07343894619429, 82.28655899073526 33.37740148141864, 88.32584784035213 26.429994386737274 M81.5038007263856 40.374874206040886 C83.683618584539 37.86728060852505, 85.8634364426924 35.35968701100921, 88.06439101629068 32.82777840381317 M81.5038007263856 40.374874206040886 C83.62134083128937 37.938922968336136, 85.73888093619314 35.50297173063139, 88.06439101629068 32.82777840381317" stroke="#fa5252" stroke-width="0.5" fill="none"></path><path d="M0 0 C32.98184273473924 0, 65.96368546947848 0, 85.70000000000013 0 M0 0 C32.54269795306032 0, 65.08539590612064 0, 85.70000000000013 0 M85.70000000000013 0 C85.70000000000013 9.08658194616437, 85.70000000000013 18.17316389232874, 85.70000000000013 39 M85.70000000000013 0 C85.70000000000013 10.802469717711212, 85.70000000000013 21.604939435422423, 85.70000000000013 39 M85.70000000000013 39 C52.886900880411346 39, 20.073801760822562 39, 0 39 M85.70000000000013 39 C68.02522339455794 39, 50.35044678911574 39, 0 39 M0 39 C0 26.94815444871783, 0 14.896308897435663, 0 0 M0 39 C0 28.28894211128354, 0 17.57788422256708, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g></svg> \ No newline at end of file
diff --git a/backoffice-tip-create.confirmation.svg b/backoffice-tip-create.confirmation.svg
deleted file mode 100644
index 50e8c0b4..00000000
--- a/backoffice-tip-create.confirmation.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 571.8889058430991 551.2222391764319" width="571.8889058430991" height="551.2222391764319">
- <!-- svg-source:excalidraw -->
- <!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO2caVPiSlx1MDAxN8ffz6ewmLdjpvflvtNRwd1cdTAwMTFwmaduWVx1MDAxMVx1MDAwMkRcdTAwMDKBXHUwMDEw1lv3u99cdTAwMTNQiFmYaIlm5pmURUlcdTAwMTbS6f6d0/9zujv/fNraKvjTnlX4a6tgTWqmY9c9c1xc+Fx1MDAxMuxcdTAwMWZZ3sB2u3CIzL9cdTAwMGbcoVebn9ny/d7gr69fV1dcdTAwMTg1t7O4ynKsjtX1XHUwMDA3cN7/4PvW1j/zz9B9PKvmm92mY80vmFx1MDAxZlrdikpcdTAwMTXde+Z257fFhEosuF5cdTAwMWW3XHUwMDA3e3A336rDwYbpXGas1ZFgV1x1MDAwMZ1Zlmz1XHUwMDFi7nfbLlx1MDAxZVxcNe4n4q60umnDdpyyP3VcdTAwMTaPZNZaQy9UpIHvuW3r2q77reDekf3L61x1MDAwNi5UwOoqz1x1MDAxZDZbXWtcdTAwMTA8PlrudXtmzfanwe+g1d5FXHUwMDFkhM+bXHUwMDA0Z1AuXHJJXHUwMDE1YlghqjlcdTAwMTLLw/NcdTAwMWaghFx1MDAxYZgoojAhRGpcIlwiJfvmOq5cdTAwMTeU7DOab6uy3Zu1dlx1MDAxM1xu2K0vz/E9szvomVx1MDAxZTTY6rzx4zNzjlxypZRGXFwxirRe1UHLspstPziFYlx1MDAwM4pBqMZSMEpWZbHmrYIx4lx1MDAwNLHQpUFcdTAwMDF6h/U5XHUwMDFlf0crtWV6vcfKK1xmgi+hwlx1MDAwN+XeX7D1dPn82L9fkinzrYmfXHUwMDA0XHUwMDE4XHUwMDExMlx1MDAxNTCNlZaM8cyEeUWvR0o7u/rq9vL2cHy+U1H45P1cYsOvI4xRQEhcdTAwMTEmNNFAXHUwMDE5U1x1MDAxMcJcdTAwMDQ2hKKKU0lcdOeKbIwwolicqThFXFxxIIxcdTAwMTG9XHUwMDExilat5Xb9sj2z5lx1MDAwNXu298Ds2M70yVx1MDAxMS4wXHUwMDBi8IJcdTAwMWJU7N5WzbNMYGRrMKzVrEFj6MC5oTpcdTAwMTlYjt2d/6p4dvmOYzdcdTAwMDNcIlx1MDAwYo7VeI6qb4NfXVx1MDAxZfbdXuF1qCuRhrpWjGsqJc6M+rjpXFzYfZ9dXHUwMDFl3lx1MDAxZbRcdTAwMGXrvZm135/m3pkyTFxyQThcdTAwMTWCSs4jrpRxZVx1MDAxMCZcdTAwMTEhXFxcdTAwMTJF2eZcXGnI5yw5JzTKOUFcdTAwMWFKglno7I2DjrKCbnbgJ/1ErrHaXGbXa4VcdTAwMDLDPFxybvBgnFwigTjNTHfrUlxmeqd6rK1W0S19R6VcdTAwMDfbOsg93Vx1MDAwMnODSFx1MDAxNbhpRjWKSlx1MDAwNca5IYApXGamzlx1MDAxMZGb41x1MDAxYsOddGiTSbwrg1wixiRdfPK4WGCgIbAgXHUwMDFi8vOvc6FcdTAwMWOnUcZcdTAwMDVoMKR0dlx1MDAxN3qKO/bxpL93Tu5cdTAwMDfDSu1cdTAwMWWXr/3b3EPGMEt3oVx1MDAxY4NYXHUwMDE1XHUwMDA0KeidXHRccnXnb02Y1lx0RMU8KFx1MDAxNppcdTAwMDNcXCBLc+hBXHUwMDFmhlx1MDAwM99ugFx1MDAwYvRcdTAwMDO23tORptFNaXqwJSW0NyFcIjveP5o/XHUwMDBlXHUwMDFhvDhzurWWdz6rltDo+iz/eFx1MDAxM2wwRDGRXHUwMDE4Qlx1MDAxY1wiI2JYQFx1MDAxMEQhuCFEgV6iXHUwMDFi4zubQqCg2lx1MDAxOFx1MDAxNSSPePughKuXJ/lRXGJU6jS6obNUREuaPZcwLlx1MDAxZdjbpdnp7YNse768d1x1MDAwZbyZnXu4OWdcdTAwMDZcdTAwMTZAL8R8gLYmz+GeXHUwMDBiXHUwMDA0plx1MDAxNUKgXHUwMDBmXHUwMDA03lxcoFx1MDAwN1x1MDAxMSVcbm9cdKlcdTAwMDSQXHUwMDA3WLPlJjWPwk8wXHUwMDE2XHUwMDEwtTK6XHUwMDEx+F/lQEGtrImwXHUwMDE05So7YXtcdTAwMTd2iVx1MDAxNFH1x953VpuUr0tH/aNK/lx0XHUwMDEzyIDQiSiFtFx1MDAwNp5UlLD3XG6xXHUwMDE4SWAq7kC1QEgp8Y6phMxcdTAwMGW0Wt57kfOswZ0tb4377Nj1OrTZ6z0olql4Y07AjCGyyJ4sq7W3jyfV6ezo29GBPz3lpGmeXHUwMDFk51x1MDAxZvD1LpSDfEBcdTAwMWNcdTAwMGJcYjeZXGLX15vnyoQ2wP1xIHj+maBcdTAwMTcwXCLzbOzThmVcdTAwMTR/XHLBoGCCf0A+di1oJFx1MDAxNKrHQOMgU5lcYoWUP1x1MDAwM80x7YtSu7G7PzlcdTAwMTdcdTAwMGanxSn2On7+hSg8J5BcdTAwMDRtgyg0UkyHMmlgiTjDXHUwMDFhfKlmm1OicFx1MDAxN0MyXHUwMDA08lx1MDAxZtw15Ywk5WhRlCwswctTXHUwMDE2lshcdTAwMWJHa9Hak9Ld8FCcXFxbvb5f5Xd7hzM9latfS+7CXHUwMDFmpT8zXHUwMDE4lloqpjFGOFLlXHUwMDEyYltccj08J1xmOrdw1/ZUVYrGqybU58RcdTAwMWL6rdrqo1x1MDAxMX5t0y4zPYpiXG5cdTAwMTI8Nlx1MDAxNFx1MDAxM3Tk6a5cdTAwMDC8r1Ba6SyiKk5Rd+g4sU53XHUwMDE0XGZgblxyu77thKr3pd33S1x1MDAwMprkLv71vlx1MDAxM3qD1Fxuo4C3XHUwMDAyZZ9dhZ5Nv1x1MDAwZrarcvvHxJveN8r9fmfUT8tRRVx1MDAwMPqw8axAg4L0hFx1MDAwZVpjJXUolF7YMeJcdTAwMDZHXHUwMDFjJKrgQrNQz/lcbnP83Gg0XHUwMDEyfCYjXHUwMDA2RCxweyokuM2kbFx1MDAxNVx1MDAxNcbqOFWSRa2CaKbA64aaM2xmj/tgL25+r9dvxHW1zLtcdTAwMGaNabvS3r9cdTAwMWEty1x1MDAxNGBz5l7soHJtdNhxy9eNi1J/xzkrPFx1MDAxZf+YOImlJpq04oyCfMqOqLlz0FLn++rWrXWt89NSV15eXeZcdTAwMWRRzVxy6Njnf1x1MDAxMFx1MDAwZkU7XHUwMDFhbGhcdTAwMDExL1x0cuMhY31ccp/PTljyieI8kliAzThccrRhSvL0nfh6iVx1MDAxM15cdTAwMTX0yZ1/zUVeXHUwMDE1q/S4XHRkuYBAOFNcdTAwMWa24N3at/Slq8ZHXHUwMDFlaez22/1L1u6kydm88Fx1MDAwZarJXHUwMDEw63hnOeCdXHUwMDA0PaNWSP3M4/5cdTAwMDE+U7YgPVx1MDAxOYa1okFts+zUXHUwMDBmadPbtlx1MDAxZfjukdxunl/ss+Jeg+ecelx1MDAxOVxmlaVSj9jbUa+EsrSIg09B6iRIj/Dep1RcdTAwMDDIaK6VSo7X8iAmflx1MDAwMlx1MDAxYkqDTUFIx6Wi2TNT11x1MDAwZo32bGBcdTAwMWWc7N5cdTAwMTCNrVG9WJ2kpV7zw9o6XHUwMDBmXHUwMDBiknezXHUwMDFlliZgpqOMcSapXHUwMDA0MZw8nyX/jKWHoopcdTAwMDbJz+wpqdnk4Hr7crtyV1x1MDAxMsP2pKNbN7r+kHfCgpmmaYRcdC3eTrOmeTNcdTAwMTFnXGbHwiasXHUwMDE5lVxiqZRxofxTlu7JMJFcdTAwMTRrjF5cdTAwMTC/d9BcZlx1MDAxZJ82pj92K5ei3S6OXFx2dJV30Kj6XHUwMDE1QFOEKIwpzS9nc/WXhFx1MDAxOE2dXGKKOVx1MDAxNlwiXHUwMDE4U8jeW9rjc1x1MDAwYlW/nfW7h2TW7Lf65cZVK/eI4XXxXGLdvDJDScKMiLgwI9CvKM4+VpiFLjc9f9fu1u1us1x1MDAxMMmhWt16ypGea4eXgFx1MDAwNNvqv61V48y/LP//+0vy2as6XG62oM5Wl8Se1zFcdTAwMDf+N7fTsX0g+FwiKEe0cPNH2vE8d9yyzHrCQ0WPvdLm1kRDWlxiySh+wdgpL5ZbZ2jv5NC52b3qifaP5s113m2OkHU5L/JRNqeiXHUwMDE2p1x1MDAxNKdcXFwi/cfink6IWJz6XHUwMDE17C1dRlx1MDAxMU5cYqfsXHUwMDA1I8ju/o58uO/vnlfGO4O94Z3VnnXynmKW7Cdd3MZVXHUwMDE0TjS3hNxcdTAwMDP0cJTnI+mWXHUwMDAza8NcdTAwMTFr479I/5Y6pEM0XHUwMDBmIEPZ7e20OFx1MDAxMros++OLITk9UfSoU2nmPtnH0Vx1MDAxYXsjbzikk5rsS5iZXHUwMDExn5iBOSX02UTu/3N7217VW+T8/Fx1MDAxYVx1MDAxYkvPXHUwMDExSMm5XHUwMDA0rZV9ov7wou669Vx1MDAxMml5buWkV7o5b5lnaYud8mRt6WKSonewtqQkQdTawCGA0CDyT+f2uG2vqi3YcFx1MDAwZYxtYVx1MDAwNPzoxGp3Kt3R6LCIm/XxpEGPL+LTxlx1MDAxMlJ3i1x1MDAwMU6lIH7hXFxTjbiQobdcdTAwMTIsiFTEQMAsoVxuXHUwMDAzkCHnu1x1MDAxNEtUXHUwMDE4XCK08YT5y1RcdTAwMWFSSlx1MDAxNcx7XHUwMDE3WMvQmPGbTC37rEhNYyvF8n/BaWWYIIEwZ7E1e4V5LjXNhVxuoYJcdFx1MDAxYVwiy3LR5Gllazir8H7Tcpx+2dm+vrqVXHUwMDBmpVx1MDAxZNRyM01PlFx1MDAwNFx1MDAwNIaC9lx1MDAwN9+uIXqJIaZcZkFcdTAwMTFnnFx0TClcdTAwMTYxxGSSXHUwMDFjf+Ppib9cdTAwMWJDRFx1MDAwNItQkUhCaM34NueEI6wzzYbPODOx5nZ9uztcZldtTqYlLsC+vVx1MDAxMJ3jOj1lx5NL/77kTlx1MDAxZU5cdTAwMWG32Vx1MDAxZKhcZvyfJlhcbq1cYuM4QrdgwlBcdTAwMTAkXHUwMDAy2YxzhkiMbsVcck24hlx1MDAwZZdcdTAwMDTL95KGvbFcdTAwMDHCXHUwMDE35Fx1MDAxMeWaiWfvSnlcdTAwMWL2WU1YqZNcdTAwMTJ+PfYxaElccuyT2Lq5wJmwNPiV0FTQTCudXuw9e3Uq0Ghv0nPbZ6Z7tFs6XHUwMDFk3OBs3pMxg7Eg64OJwiF7Xi7rJFxcSYVcdTAwMTCjOrRueek7k2ZcdTAwMTC9te/8zfjhhFx1MDAxMcU0SpzVndr7QnRKXHUwMDE1JyRLtiCz6+xNt4ZeXHUwMDBlZ3QvqK6K26PWZDLpVPx7Wrzj3vR80s9ENSPCXHUwMDAwPYlcdTAwMDTUXHUwMDE5ojJCNVx1MDAwM8WAlFIoWC4jw2HScpXcO2D9e65YXHUwMDAwqY+pir88qlx1MDAxMFx1MDAxZT2OJsKCd7lcdTAwMTBBMr1RKiPbXHLv8U1rXHUwMDFmxLVcXMP11cxcdTAwMWS1XHUwMDFm3Gvb8/fuqrf3pmLbXHQxVVx1MDAwMtdQu1x1MDAwNlx1MDAwNUlcdTAwMDD0UqbBPUfAxlx1MDAxMOBrqYJVOIFYj4NcdTAwMWSeq/OH7Fx1MDAxN5DNXHUwMDE4gjA27EpWYKevytOKUk15plx1MDAxMcysK3HsuuVu9Vx1MDAwMG/3+Vx1MDAwYjI+jPFPj9mJgtnrlX3TXHUwMDBmji2Ih0q3649lWj1cZjyCNd5NXjNcdTAwMTIsXHUwMDFi+Vx1MDAxNPzmv/9cdTAwMDFcdTAwMDQgQjsifQ==<!-- payload-end -->
- <defs>
- <style>
- @font-face {
- font-family: "Virgil";
- src: url("https://excalidraw.com/Virgil.woff2");
- }
- @font-face {
- font-family: "Cascadia";
- src: url("https://excalidraw.com/Cascadia.woff2");
- }
- </style>
- </defs>
- <rect x="0" y="0" width="571.8889058430991" height="551.2222391764319" fill="#ffffff"></rect><g stroke-linecap="round" transform="translate(10 10) rotate(0 275.94445292154955 265.61111958821596)"><path d="M0 0 C140.46 0, 280.92 0, 551.89 0 M0 0 C204.72 0, 409.45 0, 551.89 0 M551.89 0 C551.89 152.39, 551.89 304.77, 551.89 531.22 M551.89 0 C551.89 107.04, 551.89 214.08, 551.89 531.22 M551.89 531.22 C332.47 531.22, 113.04 531.22, 0 531.22 M551.89 531.22 C417.98 531.22, 284.07 531.22, 0 531.22 M0 531.22 C0 418.2, 0 305.18, 0 0 M0 531.22 C0 346.7, 0 162.17, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(85.44442749023415 48.555572509765625) rotate(0 142 16)"><text x="0" y="26" font-family="Helvetica, Segoe UI Emoji" font-size="28px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Tip created succesfully</text></g><g transform="translate(65.88732457160927 145.118741350042) rotate(0 33.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">amount</text></g><g stroke-linecap="round" transform="translate(267.5406907399499 142.480934712235) rotate(0 77.99999999999989 14.152236652236752)"><path d="M0 0 C55.83 0, 111.67 0, 156 0 M0 0 C38.38 0, 76.75 0, 156 0 M156 0 C156 7.9, 156 15.79, 156 28.3 M156 0 C156 10.3, 156 20.6, 156 28.3 M156 28.3 C117.29 28.3, 78.59 28.3, 0 28.3 M156 28.3 C96.97 28.3, 37.93 28.3, 0 28.3 M0 28.3 C0 21.43, 0 14.55, 0 0 M0 28.3 C0 22.04, 0 15.77, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(66.88732457160927 204.63380306959152) rotate(0 49.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">justification</text></g><g transform="translate(73.66508539517713 338.18934167093744) rotate(0 33.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">tip URL</text></g><g stroke-linecap="round" transform="translate(206.4295796288386 142.52151912781937) rotate(0 30.5 14.097222222222399)"><path d="M0 0 C14.45 0, 28.9 0, 61 0 M0 0 C13.99 0, 27.98 0, 61 0 M61 0 C61 10.08, 61 20.16, 61 28.19 M61 0 C61 7.45, 61 14.91, 61 28.19 M61 28.19 C41.93 28.19, 22.86 28.19, 0 28.19 M61 28.19 C41.66 28.19, 22.33 28.19, 0 28.19 M0 28.19 C0 21.41, 0 14.63, 0 0 M0 28.19 C0 20.05, 0 11.91, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(213.09624629550513 145.118741350042) rotate(0 21 11.5)"><text x="21" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">USD</text></g><g stroke-linecap="round" transform="translate(206.4295796288386 207.92332482337952) rotate(0 134.84126984126988 51.111111111111086)"><path d="M0 0 C97.82 0, 195.63 0, 269.68 0 M0 0 C87.58 0, 175.15 0, 269.68 0 M269.68 0 C269.68 23.55, 269.68 47.1, 269.68 102.22 M269.68 0 C269.68 38.76, 269.68 77.52, 269.68 102.22 M269.68 102.22 C168.96 102.22, 68.23 102.22, 0 102.22 M269.68 102.22 C192.45 102.22, 115.21 102.22, 0 102.22 M0 102.22 C0 63.99, 0 25.75, 0 0 M0 102.22 C0 69.03, 0 35.84, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(205.3184685177273 334.0422606998018) rotate(0 85.37038167317712 15)"><path d="M0 0 C58.97 0, 117.94 0, 170.74 0 M0 0 C66.44 0, 132.88 0, 170.74 0 M170.74 0 C170.74 9.84, 170.74 19.67, 170.74 30 M170.74 0 C170.74 11.46, 170.74 22.92, 170.74 30 M170.74 30 C111.07 30, 51.39 30, 0 30 M170.74 30 C121.68 30, 72.63 30, 0 30 M0 30 C0 21.78, 0 13.56, 0 0 M0 30 C0 20.57, 0 11.13, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(76.67993668715121 404.7879712581632) rotate(0 41.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">valid until</text></g><g stroke-linecap="round" transform="translate(212.71710211484606 392.3770074341571) rotate(0 71.39795918367349 18.459183673469397)"><path d="M0.56 1.22 L141.57 0.94 L141.78 38.25 L-1.25 38.38" stroke="none" stroke-width="0" fill="#fff"></path><path d="M-0.98 1.62 C34.12 -1.49, 68.83 -1.89, 142.94 -0.88 M0.57 -0.59 C29.47 0.89, 57.16 -0.08, 142.07 0.14 M142.91 -0.64 C143.04 15.1, 140.92 25.51, 142.3 36.46 M141.87 -0.37 C142.21 8.72, 143.63 15.39, 141.94 37.29 M144.77 37.32 C105.38 36.8, 65.06 35.87, 0.85 37.03 M142.32 37.91 C86.66 35.41, 32.17 35.36, 0.24 37.86 M1.37 35.32 C1.21 25.05, 1.19 10.31, -0.4 -0.05 M-0.02 37.73 C0.2 26.83, -0.88 18.04, -0.59 0.08" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(247.36506129851932 398.8361911076265) rotate(0 5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(277.8650612985193 398.3361911076265) rotate(0 5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g stroke-linecap="round" transform="translate(366.8650612985193 391.3361911076265) rotate(0 17.75 17.75)"><path d="M0.94 -1.01 L36.83 -1.25 L36.96 34.45 L-0.83 36.6" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-1.6 -0.35 C6.91 0.23, 16.94 -1.91, 34.19 0.08 M0.95 -0.04 C12.64 -1.04, 25.48 0.32, 34.73 -0.09 M37.19 -1.59 C34.07 10.35, 34.93 20.04, 35.6 37.4 M36.19 0.82 C34.7 6.51, 35.74 14.48, 34.58 35.73 M35.05 35.71 C19.96 36.63, 7.29 37.51, -0.4 33.62 M35.33 35.31 C26.31 35.42, 18.5 35.89, -0.89 34.55 M1.85 36.37 C1.11 22.03, 0.24 8.62, 1.34 1.61 M-0.36 34.87 C0.29 24.35, -0.21 14.65, 0.61 -0.61" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(367.8650612985193 392.3361911076265) rotate(0 17.5 4.5)"><path d="M-1.01 1.33 L33.75 1.46 L33.95 8.17 L1.1 7.74" stroke="none" stroke-width="0" fill="#000"></path><path d="M-0.35 -2 C13.48 -0.6, 24.68 -1.03, 35.08 1.14 M-0.04 -0.02 C7.69 -0.19, 17.48 -1.1, 34.91 0.05 M34.28 -0.59 C34.8 2.2, 34.28 4.86, 35.86 8.17 M35.37 -0.3 C34.56 2.54, 34.82 4.33, 35.1 9.44 M35.21 7.62 C24.64 9.03, 14.32 8.52, -1.88 8.05 M34.81 8.78 C21.27 9.88, 7.77 8.05, -0.95 9.68 M0.39 9.37 C-0.22 7, -0.37 5.64, 0.73 -0.02 M-0.28 9.26 C-0.31 5.6, 0.09 2.41, -0.28 0.21" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(375.3650612985193 383.8361911076265) rotate(0 3 7)"><path d="M1.33 -1.25 L7.46 -1.05 L5.17 15.1 L-1.26 12.71" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-0.6 0.04 C1.4 -0.59, 2.93 0.04, 6.34 -0.36 M-0.01 -0.22 C2.36 0.19, 4.41 -0.02, 6.02 -0.1 M5.08 -0.34 C5.8 3.42, 6.19 10.47, 4.71 13.49 M5.53 -0.6 C6.36 3.16, 5.45 6.86, 6.69 14.14 M5.59 14.26 C3.76 14.53, 1.34 13.44, -0.28 14.6 M5.93 14.07 C5.03 14.2, 3.24 13.7, 0.21 13.76 M0.58 13.72 C-0.16 8.67, 0.81 5.49, -0.03 1.14 M0.41 13.59 C0.11 9.37, 0.48 3.91, 0.33 -0.35" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(390.3650612985193 383.8361911076265) rotate(0 3 7)"><path d="M-1.25 1.46 L4.95 -0.83 L7.1 12.74 L-1.29 14.58" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0.04 -0.26 C0.72 -0.33, 2.67 0.4, 5.64 0.52 M-0.22 0.04 C2.56 -0.23, 4.71 0.02, 5.9 0.08 M5.66 -0.32 C4.73 5.45, 7.22 9.47, 5.49 13.15 M5.4 0.26 C5.93 4.52, 6.28 11.02, 6.14 14.55 M6.26 14.03 C4.85 13.84, 2.11 13.67, 0.6 13.45 M6.07 14.28 C4.52 13.72, 2.32 14.19, -0.24 14.13 M-0.28 13.97 C-0.57 9.44, 1.07 2.97, 1.14 0.63 M-0.41 14.06 C0.28 10.73, -0.34 6.93, -0.35 0.47" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(383.8650612985193 400.3361911076265) rotate(0 0.6422718642013479 13.197904566302896)"><path d="M-0.88 -1.99 C-1.43 7.57, 1.15 13.78, 2.24 28.39 M0.14 0.63 C-0.63 7.75, 0.34 15.35, 0.76 27.34" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g stroke-linecap="round"><g transform="translate(374.3650612985193 399.3361911076265) rotate(0 0.19790456630289555 13.301320007070899)"><path d="M-1.99 -1.31 C0.2 6.74, -0.97 12.94, 2.39 27.91 M0.63 -0.77 C-0.14 8.39, -0.23 16.93, 1.34 27.2" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g stroke-linecap="round"><g transform="translate(393.8650612985193 400.8361911076265) rotate(0 0.2720004984978459 12.683548028115183)"><path d="M-1.31 0.08 C1.49 6.67, 2.55 17.58, 1.41 25.45 M-0.77 -0.09 C0.43 5.46, 0.98 12.41, 0.7 24.84" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g stroke-linecap="round"><g transform="translate(402.8650612985193 408.8361911076265) rotate(0 -17.287554731126875 -0.13689562075796857)"><path d="M0.08 1.14 C-9.9 1.52, -15.53 -0.31, -34.05 -1.46 M-0.09 0.05 C-10.99 0, -20.5 -1.06, -34.66 -0.25" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g stroke-linecap="round"><g transform="translate(402.3650612985193 417.8361911076265) rotate(0 -18.16205287910998 0.04547248221933842)"><path d="M1.14 -1.19 C-5.48 2.11, -14.51 0.37, -37.46 1.28 M0.05 -0.32 C-12.82 1.18, -26.96 0.04, -36.25 0.77" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g stroke-linecap="round" transform="translate(340.7275521017252 468.94674259140356) rotate(0 68.33333333333326 18.888905843098996)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.26 6.4 C1.09 4.84, 2.44 3.29, 4.99 0.36 M-0.26 6.4 C1.46 4.42, 3.17 2.45, 4.99 0.36 M0.13 12.04 C2.6 9.2, 5.07 6.36, 10.63 -0.03 M0.13 12.04 C2.36 9.48, 4.59 6.92, 10.63 -0.03 M-0.13 18.44 C3.98 13.71, 8.09 8.98, 15.62 0.33 M-0.13 18.44 C3.41 14.36, 6.95 10.29, 15.62 0.33 M0.27 24.08 C6 17.49, 11.72 10.9, 21.26 -0.07 M0.27 24.08 C7.46 15.81, 14.65 7.53, 21.26 -0.07 M0 30.48 C5.48 24.19, 10.95 17.89, 26.25 0.29 M0 30.48 C9.05 20.07, 18.1 9.66, 26.25 0.29 M-0.26 36.88 C8.64 26.64, 17.54 16.41, 31.89 -0.1 M-0.26 36.88 C12.31 22.42, 24.88 7.96, 31.89 -0.1 M2.11 40.26 C13.59 27.05, 25.06 13.85, 36.88 0.26 M2.11 40.26 C12.5 28.3, 22.9 16.34, 36.88 0.26 M7.75 39.86 C19.43 26.42, 31.11 12.99, 42.52 -0.14 M7.75 39.86 C18.98 26.94, 30.22 14.01, 42.52 -0.14 M12.74 40.22 C24.86 26.28, 36.98 12.33, 47.51 0.22 M12.74 40.22 C20.81 30.93, 28.89 21.64, 47.51 0.22 M18.38 39.83 C31.65 24.56, 44.91 9.3, 53.15 -0.17 M18.38 39.83 C28.39 28.31, 38.41 16.79, 53.15 -0.17 M23.37 40.19 C36.54 25.03, 49.71 9.88, 58.14 0.19 M23.37 40.19 C34.58 27.29, 45.8 14.38, 58.14 0.19 M29.01 39.79 C38.99 28.31, 48.97 16.82, 63.78 -0.21 M29.01 39.79 C40.04 27.1, 51.07 14.42, 63.78 -0.21 M34 40.15 C41.91 31.05, 49.83 21.94, 68.77 0.15 M34 40.15 C43.74 28.94, 53.49 17.73, 68.77 0.15 M39.64 39.76 C52.44 25.03, 65.24 10.31, 74.41 -0.24 M39.64 39.76 C47.47 30.75, 55.31 21.73, 74.41 -0.24 M44.63 40.12 C54.86 28.34, 65.1 16.57, 79.4 0.12 M44.63 40.12 C53.28 30.16, 61.94 20.2, 79.4 0.12 M50.27 39.72 C60.09 28.43, 69.91 17.13, 85.04 -0.28 M50.27 39.72 C61.03 27.34, 71.8 14.96, 85.04 -0.28 M55.26 40.08 C64.66 29.27, 74.06 18.46, 90.03 0.08 M55.26 40.08 C65.85 27.89, 76.45 15.7, 90.03 0.08 M60.9 39.69 C72.37 26.49, 83.85 13.29, 95.67 -0.31 M60.9 39.69 C69.59 29.69, 78.29 19.68, 95.67 -0.31 M65.89 40.05 C74.2 30.49, 82.51 20.92, 100.66 0.05 M65.89 40.05 C78.29 25.78, 90.69 11.52, 100.66 0.05 M71.53 39.65 C83.8 25.54, 96.08 11.42, 106.3 -0.34 M71.53 39.65 C78.82 31.27, 86.11 22.88, 106.3 -0.34 M76.52 40.01 C89.61 24.96, 102.7 9.9, 111.29 0.02 M76.52 40.01 C85.09 30.16, 93.66 20.3, 111.29 0.02 M82.16 39.62 C90.2 30.37, 98.24 21.12, 116.27 0.38 M82.16 39.62 C93.56 26.5, 104.97 13.38, 116.27 0.38 M87.15 39.98 C95.85 29.97, 104.55 19.96, 121.92 -0.02 M87.15 39.98 C95.8 30.03, 104.45 20.07, 121.92 -0.02 M92.79 39.59 C99.78 31.55, 106.76 23.51, 126.91 0.34 M92.79 39.59 C101.4 29.69, 110 19.78, 126.91 0.34 M97.78 39.95 C108.93 27.11, 120.09 14.28, 132.55 -0.05 M97.78 39.95 C110.68 25.1, 123.59 10.25, 132.55 -0.05 M103.42 39.55 C114.64 26.64, 125.86 13.73, 137.54 0.31 M103.42 39.55 C116.21 24.83, 129.01 10.11, 137.54 0.31 M108.41 39.91 C115.34 31.93, 122.28 23.95, 137.27 6.7 M108.41 39.91 C115.74 31.48, 123.06 23.05, 137.27 6.7 M114.05 39.52 C119.08 33.73, 124.11 27.95, 137.01 13.1 M114.05 39.52 C123.16 29.04, 132.27 18.56, 137.01 13.1 M119.04 39.88 C125.53 32.41, 132.02 24.95, 137.41 18.74 M119.04 39.88 C123.99 34.17, 128.95 28.47, 137.41 18.74 M124.02 40.24 C128.33 35.28, 132.63 30.33, 137.15 25.14 M124.02 40.24 C129.2 34.28, 134.37 28.33, 137.15 25.14 M129.67 39.84 C132.79 36.25, 135.91 32.66, 137.54 30.79 M129.67 39.84 C131.44 37.8, 133.21 35.77, 137.54 30.79" stroke="#82c91e" stroke-width="0.5" fill="none"></path><path d="M0 0 C49.47 0, 98.93 0, 136.67 0 M0 0 C42.29 0, 84.59 0, 136.67 0 M136.67 0 C136.67 8.33, 136.67 16.66, 136.67 37.78 M136.67 0 C136.67 8.06, 136.67 16.12, 136.67 37.78 M136.67 37.78 C93.85 37.78, 51.03 37.78, 0 37.78 M136.67 37.78 C88.21 37.78, 39.74 37.78, 0 37.78 M0 37.78 C0 24.21, 0 10.64, 0 0 M0 37.78 C0 27.5, 0 17.22, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(372.94974041552723 475.50226423853906) rotate(0 37.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">continue</text></g><g stroke-linecap="round" transform="translate(388.95413517850125 333.70723212274766) rotate(0 42.96295166015625 15.66137767973396)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.26 6.4 C1.33 4.57, 2.92 2.74, 4.99 0.36 M-0.26 6.4 C1.67 4.17, 3.61 1.95, 4.99 0.36 M0.13 12.04 C4.31 7.24, 8.49 2.43, 10.63 -0.03 M0.13 12.04 C4.25 7.31, 8.36 2.58, 10.63 -0.03 M-0.13 18.44 C4.4 13.23, 8.93 8.02, 15.62 0.33 M-0.13 18.44 C6.09 11.29, 12.3 4.14, 15.62 0.33 M0.27 24.08 C6.1 17.37, 11.93 10.66, 21.26 -0.07 M0.27 24.08 C8.03 15.15, 15.79 6.22, 21.26 -0.07 M0 30.48 C7.44 21.92, 14.88 13.36, 26.25 0.29 M0 30.48 C9.23 19.87, 18.45 9.26, 26.25 0.29 M2.37 33.86 C8.28 27.06, 14.18 20.27, 31.89 -0.1 M2.37 33.86 C11.1 23.81, 19.83 13.77, 31.89 -0.1 M8.01 33.46 C18.87 20.98, 29.72 8.49, 36.88 0.26 M8.01 33.46 C15.44 24.92, 22.87 16.37, 36.88 0.26 M13 33.82 C24.34 20.78, 35.68 7.73, 42.52 -0.14 M13 33.82 C20.91 24.72, 28.83 15.61, 42.52 -0.14 M18.64 33.43 C27.12 23.68, 35.59 13.93, 47.51 0.22 M18.64 33.43 C27.73 22.98, 36.81 12.53, 47.51 0.22 M23.63 33.79 C30.77 25.58, 37.9 17.37, 53.15 -0.17 M23.63 33.79 C30.05 26.4, 36.47 19.01, 53.15 -0.17 M29.27 33.39 C38.11 23.22, 46.96 13.05, 58.14 0.19 M29.27 33.39 C35.28 26.48, 41.29 19.57, 58.14 0.19 M34.26 33.75 C42.43 24.35, 50.6 14.95, 63.78 -0.21 M34.26 33.75 C40.39 26.7, 46.52 19.64, 63.78 -0.21 M39.9 33.36 C49.33 22.51, 58.76 11.66, 68.77 0.15 M39.9 33.36 C45.83 26.54, 51.75 19.73, 68.77 0.15 M44.89 33.72 C56.26 20.63, 67.64 7.55, 74.41 -0.24 M44.89 33.72 C54.79 22.33, 64.69 10.95, 74.41 -0.24 M50.53 33.33 C56.58 26.37, 62.62 19.42, 79.4 0.12 M50.53 33.33 C57.93 24.81, 65.34 16.29, 79.4 0.12 M55.52 33.69 C66.01 21.61, 76.51 9.54, 85.04 -0.28 M55.52 33.69 C62.29 25.89, 69.07 18.1, 85.04 -0.28 M61.16 33.29 C67.92 25.51, 74.68 17.74, 88.06 2.35 M61.16 33.29 C69.1 24.16, 77.03 15.03, 88.06 2.35 M66.15 33.65 C74.36 24.21, 82.56 14.77, 88.45 7.99 M66.15 33.65 C74.01 24.61, 81.87 15.57, 88.45 7.99 M71.79 33.26 C76.57 27.76, 81.35 22.26, 88.19 14.39 M71.79 33.26 C77.32 26.9, 82.85 20.54, 88.19 14.39 M76.78 33.62 C80.26 29.61, 83.75 25.6, 88.59 20.03 M76.78 33.62 C80.31 29.55, 83.84 25.49, 88.59 20.03 M82.42 33.22 C83.67 31.79, 84.91 30.35, 88.33 26.43 M82.42 33.22 C84.67 30.63, 86.92 28.04, 88.33 26.43" stroke="#4c6ef5" stroke-width="0.5" fill="none"></path><path d="M0 0 C34.37 0, 68.73 0, 85.93 0 M0 0 C30.8 0, 61.6 0, 85.93 0 M85.93 0 C85.93 7.3, 85.93 14.59, 85.93 31.32 M85.93 0 C85.93 10.75, 85.93 21.51, 85.93 31.32 M85.93 31.32 C64.61 31.32, 43.3 31.32, 0 31.32 M85.93 31.32 C64.26 31.32, 42.59 31.32, 0 31.32 M0 31.32 C0 19.26, 0 7.2, 0 0 M0 31.32 C0 20.81, 0 10.29, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(396.7054353242104 338.1304988211914) rotate(0 35 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">copy url</text></g><g transform="translate(78.68102157642033 106.96052345493217) rotate(0 20 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">from</text></g><g transform="translate(211.63556703096583 97.86961436402316) rotate(0 71.5 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">video promotion</text></g></svg> \ No newline at end of file
diff --git a/backoffice-tip-create.svg b/backoffice-tip-create.svg
deleted file mode 100644
index a5c53faa..00000000
--- a/backoffice-tip-create.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 493 527.3333587646484" width="493" height="527.3333587646484">
- <!-- svg-source:excalidraw -->
- <!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO2aXXPaOFx1MDAxNIbv91cw7O3G1dG3etc0JGnzVSBtmuzsZFx1MDAxY2PAwbHBNlx1MDAxMLLT/77HJlx1MDAwNVx1MDAwN2xK0iXlorpgQLaQLD169Z5cdTAwMDP//lGpVJNJ362+rVTde8f2vVZkj6t/pfUjN4q9MMBLNPtcdTAwMWOHw8jJ7uwmST9+++bNvIXlhHfTVq7v3rlBXHUwMDEy431/4+dK5d/sNddP5DqJXHUwMDFkdHw3a5BdmnfFQCzWnoZB1i1oqqkkVKrZXHUwMDFkXryH/SVuXHUwMDBiL7dtP3bnV9KqKmlDg1+2duv7XVVzj+Wnzu7Vh3m3bc/3m8nEnz6U7XSHUW5QcVx1MDAxMoU998JrJd2094X6Wbs4xCmYt4rCYadcdTAwMWK4cTpcdTAwMDFkVlx1MDAxYvZtx0sm6feQee10XHUwMDE28vfd4yfFhUVBKo4vXFxcYq1nV7P2jCqLS05AMc2FpotcdTAwMDN7XHUwMDFm+mGUXHUwMDBl7E+SlfnQbmyn18HxXHUwMDA1rdk9SWRcdTAwMDdx345wxeb3jVx1MDAxZlx1MDAxZpkrNqvrul6nm2ClIMpiWIRWXHUwMDEyh6H5vHs3W1x1MDAwN+BCXHUwMDExQ7iaL2Taaf9DK2Pin8V57NpR/3G+qnH6ITfgdKy1KVDfm2fXvv1VjFbi3idFVIHRpVRcdTAwMDFcdTAwMTDNmDLrU9Wpx/bt6WDiXHUwMDA0t0fRuLFvjztf9l+PKnhcdTAwMTFVmlx1MDAxMktKXHUwMDAwaaTgyjC6QJWUXHUwMDE2XHUwMDAxI7TRhjOu1MaoXHUwMDAyWUBVbjiPXHUwMDE4aWq0MpyajVA0X6wwSJreQzpfVD+p3bfvPH/yXf2mmKV4YVx1MDAwN++GSTeMsFXl3Mt3ZMeu71x1MDAwNdl3iSeN3vleJ+Ww6rvtp4AmXHUwMDFlSujsclx1MDAxMvarL1x1MDAwMpzyUtlcdTAwMTTMXHUwMDEwokluO/6I76ZkX6+b8eee09o9csjHi1x1MDAxZMHb266amoBcdTAwMDWEXHUwMDEzKVx1MDAxNZMgNXvKN5fUQrFUKFtcZt+zzfGdO55meFO2iLdSlHNcdTAwMDNcZl5cdTAwMGZvsi7e9lx1MDAxZH5lUsg16M1wvdpcdTAwMTMoXlx1MDAwNjfKXHUwMDE5Z4Zqsj7dSe2hW+veXn4hjeaZX2vRXHUwMDExnD1sO914XHUwMDA3tZRQnFE8Wlx1MDAwNdFyXHUwMDAxb2Esg0BcdEqM1LBB9Vx1MDAxNsIyuaKKaNdcdTAwMTYjXHUwMDFj3cP0VSxpO1A0MVTBXHUwMDE2OVx1MDAwNFxupIwxo6jG3UrXN1xisX/Waun43VFcdTAwMTLQ+vveUVxy6l/6246YRsJWXGKooNRcIkahjeCCo/eUXHUwMDFiQ8yYXHUwMDAypJZcdTAwMDRcdTAwMTTAXHUwMDE4aqhcdTAwMTTbqKC3wzjx2iiBSUrXa1xuaSnfrNxcdTAwMDFcdTAwMTPcp5JcdTAwMDCBtVx1MDAwMb84XGZvO3bg9O5P9mpHV/HhXHUwMDE5xHT7XHUwMDAx51x1MDAxNsezXHUwMDA04ZRGkJxIZu3RXHUwMDE2W4JTijGN0Vx1MDAxMoPNzWkowFqEK1xcXHUwMDE2yslmVPLnXHUwMDAw/9w4rtjtxI0qSYlcdTAwMDP+NU5hXHUwMDA15VxmXHUwMDBmXHUwMDFkTZhZ3ylcdTAwMDSDwO7tnXbPrpvn3v7koj+x+4fbTrnhYGFgzihgkMdMzjrNjYJcdTAwMTaCoXBcIlvANka5XHUwMDA0i+RLXHUwMDEx89pcdTAwMDJ0Ld+Lyq3NbFx1MDAwZjD0yYKJV7RcbtPFP5lcdTAwMWM0xMfk8POVe/yhpmvMY040/7ZivZ0uXHUwMDAw2lx1MDAxZsDoVaOoXHUwMDEyuTj/pXHILOtCXHUwMDBiJoqtWPX/a+F+Nc8vXdhZ3omhb+Egllwi4cxxwmLtXFxcdTAwMTiwJdpmNp/jcmFYhihcdTAwMTj6/rI8Nvdy8/pcXIGdiaGDvbjRXG61vPNarbxcdTAwMTI+0d9cdTAwMTVwXHUwMDBmh/W929Od1nWbXe80ertn51x1MDAxN/FgXHUwMDE57lx1MDAwMq1dQ2JcdTAwMDRcdTAwMTVcdTAwMTZL8aaUKINLsoQ4pVx1MDAxOKvnyzLxgG6U5krutP69XHUwMDAzSnaARGE3kpsl1FPzU3owUkY0XHUwMDE3UppcdTAwMTfjv1x1MDAwMrRJR1xmdmv3XHUwMDAzICeNg+7O8Ct1O1x1MDAxZp9cdTAwMDFcdTAwMWGxUPsxNpOaUi1cdTAwMTdylniEWYJIqjQ+XHUwMDAx06xcdTAwMDA0UJbKXHUwMDE1XZR6XFx1ov4mK6NcdTAwMDBcdTAwMTExWqG4XHUwMDE2SauUpWjh+Vx1MDAwN5TytXKPz2BrLS9cYsKUjSvNgVx1MDAwYvqMnFG9OVKj4+H4obu7XHUwMDA38sTeXHUwMDFmQFx1MDAxYrZndctyRpRbTDGDno9cdEbEQkSvJF7G9Vx1MDAwMYGSIdlPxTt/aupcdTAwMThwl10gMGnJXFxcdTAwMTFcdTAwMDXuhmWbVFx1MDAwM0iMu4zKxf/fj3aGXHUwMDE3uNS5J/jlXHSj/PwvOlxuXHUwMDAxaW6Xs/VcdTAwMDG7dO6vhrs6OGdccv35MLxcdTAwMWONXHUwMDBmXHUwMDA34+1cdTAwMDdMSFx1MDAwYk9cdTAwMWPAo1x1MDAxZZ+XLFx1MDAwNNRKXHUwMDExXHUwMDBiwVJM4fopqfRGXHUwMDAwy9m9VbG04FJRkk/ibU8w7USunZS5uGJnuNEoXHUwMDFh6IooXHUwMDFhd2r6Y+E6bmGK9rt6r9mbfNE3XHUwMDA3XHUwMDEzV53S9/WHJrnadrQ1/4F0Mkug71x1MDAxMFxiXHUwMDE1uq5cciZD/1x1MDAxN/2kwmA1hvzbI5+y9HBGMTFEkGeIp7czuqt9fDiO7u6u6no0qN+44nbrXHRTT7VcdTAwMTNcdTAwMTZcYkPxzP6XoJniXHUwMDAwZnN5XHUwMDFhoZeJKkpGgjRqS9Ptjo3o+K9cIqBT4lx1MDAwZW9cdTAwMGU6XHUwMDBmXHL302nLXHUwMDBiXHUwMDFjR4zGo4frg3WSQ8ooS1xigedcdTAwMTBJT0a+cGRyMFx1MDAxNu5hwcBcYsJze32WXHUwMDFjXCIrXHUwMDE363dcdTAwMDBTXHUwMDEywFx1MDAxOFx1MDAwMaDxXFwrylxy0dJflynR2jDKxctj4yVW29HjP+VehvtzXHUwMDAwLtxcdTAwMGZqXHUwMDA11uRcXN9cZm6O9OBSXFzu8Xup7qPwcr2cp7SQXVwiXHUwMDE501x1MDAwNP3eQqDOKViUivRHReA4p2KJazTLv8F+XHTYKaLpv+1IXHUwMDEx2az8v5RcbrBcdTAwMTnP/3vwp8lcdTAwMWV5LTes9JHv8OnPnr9cZnJ8zaa0avf7zST12G9cdTAwMWaRx2n3Wo9jmj9cZj6CO94tXGI+2llJT4Rvf3z7XHUwMDBmXHUwMDBlXHUwMDE54yoifQ==<!-- payload-end -->
- <defs>
- <style>
- @font-face {
- font-family: "Virgil";
- src: url("https://excalidraw.com/Virgil.woff2");
- }
- @font-face {
- font-family: "Cascadia";
- src: url("https://excalidraw.com/Cascadia.woff2");
- }
- </style>
- </defs>
- <rect x="0" y="0" width="493" height="527.3333587646484" fill="#ffffff"></rect><g stroke-linecap="round" transform="translate(10 10) rotate(0 236.5 253.66667938232422)"><path d="M0 0 C131.16 0, 262.31 0, 473 0 M0 0 C111.95 0, 223.9 0, 473 0 M473 0 C473 107.96, 473 215.91, 473 507.33 M473 0 C473 117.77, 473 235.54, 473 507.33 M473 507.33 C367.62 507.33, 262.25 507.33, 0 507.33 M473 507.33 C343.17 507.33, 213.33 507.33, 0 507.33 M0 507.33 C0 342.58, 0 177.83, 0 0 M0 507.33 C0 399.36, 0 291.39, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(85.44442749023438 48.555572509765625) rotate(0 81.5 16)"><text x="0" y="25" font-family="Helvetica, Segoe UI Emoji" font-size="28px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Authorize Tip</text></g><g transform="translate(65.8873245716095 145.11874135004155) rotate(0 33.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">amount</text></g><g stroke-linecap="round" transform="translate(267.5406907399498 142.48093471223478) rotate(0 77.99999999999983 14.152236652236752)"><path d="M0 0 C59.79 0, 119.57 0, 156 0 M0 0 C43.47 0, 86.93 0, 156 0 M156 0 C156 6.15, 156 12.31, 156 28.3 M156 0 C156 10.96, 156 21.92, 156 28.3 M156 28.3 C104.75 28.3, 53.51 28.3, 0 28.3 M156 28.3 C108.41 28.3, 60.82 28.3, 0 28.3 M0 28.3 C0 20.46, 0 12.62, 0 0 M0 28.3 C0 20.37, 0 12.43, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(66.8873245716095 204.63380306959152) rotate(0 49.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">justification</text></g><g transform="translate(69.22065790494287 337.0782475140361) rotate(0 55.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">URL after tip</text></g><g stroke-linecap="round" transform="translate(206.4295796288386 142.52151912781915) rotate(0 30.5 14.097222222222399)"><path d="M0 0 C21.91 0, 43.82 0, 61 0 M0 0 C15.53 0, 31.06 0, 61 0 M61 0 C61 7.5, 61 15.01, 61 28.19 M61 0 C61 8.02, 61 16.03, 61 28.19 M61 28.19 C42.22 28.19, 23.45 28.19, 0 28.19 M61 28.19 C45.87 28.19, 30.75 28.19, 0 28.19 M0 28.19 C0 17.6, 0 7, 0 0 M0 28.19 C0 20.22, 0 12.24, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(213.09624629550524 145.11874135004155) rotate(0 21 11.5)"><text x="21" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">USD</text></g><g stroke-linecap="round" transform="translate(206.4295796288386 207.9233248233793) rotate(0 110.55555555555554 51.111111111111086)"><path d="M0 0 C44.54 0, 89.08 0, 221.11 0 M0 0 C71.21 0, 142.42 0, 221.11 0 M221.11 0 C221.11 37.99, 221.11 75.97, 221.11 102.22 M221.11 0 C221.11 30.08, 221.11 60.16, 221.11 102.22 M221.11 102.22 C157.92 102.22, 94.74 102.22, 0 102.22 M221.11 102.22 C136.25 102.22, 51.39 102.22, 0 102.22 M0 102.22 C0 70.18, 0 38.13, 0 0 M0 102.22 C0 65.3, 0 28.38, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(205.3184685177274 334.0422606998013) rotate(0 108.88888888888886 15)"><path d="M0 0 C60.68 0, 121.36 0, 217.78 0 M0 0 C47.35 0, 94.7 0, 217.78 0 M217.78 0 C217.78 11.62, 217.78 23.23, 217.78 30 M217.78 0 C217.78 9.86, 217.78 19.71, 217.78 30 M217.78 30 C151.34 30, 84.91 30, 0 30 M217.78 30 C157.45 30, 97.12 30, 0 30 M0 30 C0 21.59, 0 13.18, 0 0 M0 30 C0 19.86, 0 9.71, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(289.1572037707465 446.8971981070499) rotate(0 68.33333333333326 18.888905843098996)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.26 6.4 C0.87 5.1, 2 3.79, 4.99 0.36 M-0.26 6.4 C1.41 4.48, 3.08 2.56, 4.99 0.36 M0.13 12.04 C3.51 8.15, 6.89 4.27, 10.63 -0.03 M0.13 12.04 C3.27 8.43, 6.41 4.82, 10.63 -0.03 M-0.13 18.44 C4.49 13.13, 9.1 7.82, 15.62 0.33 M-0.13 18.44 C5.98 11.41, 12.1 4.37, 15.62 0.33 M0.27 24.08 C6.99 16.35, 13.71 8.62, 21.26 -0.07 M0.27 24.08 C6.62 16.77, 12.97 9.46, 21.26 -0.07 M0 30.48 C6.13 23.43, 12.26 16.38, 26.25 0.29 M0 30.48 C7.11 22.31, 14.22 14.13, 26.25 0.29 M-0.26 36.88 C8.61 26.67, 17.48 16.47, 31.89 -0.1 M-0.26 36.88 C9.73 25.39, 19.72 13.9, 31.89 -0.1 M2.11 40.26 C15.11 25.29, 28.12 10.33, 36.88 0.26 M2.11 40.26 C9.34 31.93, 16.58 23.61, 36.88 0.26 M7.75 39.86 C18.54 27.45, 29.32 15.04, 42.52 -0.14 M7.75 39.86 C21.47 24.07, 35.2 8.29, 42.52 -0.14 M12.74 40.22 C26.45 24.44, 40.17 8.66, 47.51 0.22 M12.74 40.22 C24.07 27.19, 35.39 14.16, 47.51 0.22 M18.38 39.83 C26.6 30.37, 34.82 20.92, 53.15 -0.17 M18.38 39.83 C30.86 25.47, 43.35 11.1, 53.15 -0.17 M23.37 40.19 C30.9 31.52, 38.44 22.85, 58.14 0.19 M23.37 40.19 C34.91 26.91, 46.46 13.62, 58.14 0.19 M29.01 39.79 C38.04 29.4, 47.08 19.01, 63.78 -0.21 M29.01 39.79 C37.38 30.16, 45.76 20.53, 63.78 -0.21 M34 40.15 C44.6 27.96, 55.19 15.77, 68.77 0.15 M34 40.15 C41.57 31.44, 49.14 22.73, 68.77 0.15 M39.64 39.76 C49.31 28.63, 58.98 17.51, 74.41 -0.24 M39.64 39.76 C46.94 31.36, 54.24 22.96, 74.41 -0.24 M44.63 40.12 C57.31 25.52, 70 10.93, 79.4 0.12 M44.63 40.12 C57.04 25.84, 69.45 11.56, 79.4 0.12 M50.27 39.72 C63.52 24.48, 76.77 9.23, 85.04 -0.28 M50.27 39.72 C59.63 28.95, 69 18.18, 85.04 -0.28 M55.26 40.08 C63.79 30.27, 72.32 20.45, 90.03 0.08 M55.26 40.08 C62.43 31.83, 69.6 23.58, 90.03 0.08 M60.9 39.69 C73.1 25.65, 85.3 11.62, 95.67 -0.31 M60.9 39.69 C73.22 25.52, 85.54 11.34, 95.67 -0.31 M65.89 40.05 C74.13 30.57, 82.37 21.09, 100.66 0.05 M65.89 40.05 C73.02 31.84, 80.15 23.64, 100.66 0.05 M71.53 39.65 C84.1 25.19, 96.67 10.73, 106.3 -0.34 M71.53 39.65 C79.65 30.32, 87.77 20.98, 106.3 -0.34 M76.52 40.01 C89.46 25.12, 102.41 10.23, 111.29 0.02 M76.52 40.01 C86.11 28.98, 95.7 17.95, 111.29 0.02 M82.16 39.62 C91.69 28.65, 101.23 17.69, 116.27 0.38 M82.16 39.62 C89.25 31.46, 96.35 23.3, 116.27 0.38 M87.15 39.98 C98.5 26.92, 109.86 13.86, 121.92 -0.02 M87.15 39.98 C98.39 27.04, 109.64 14.11, 121.92 -0.02 M92.79 39.59 C105.18 25.33, 117.58 11.07, 126.91 0.34 M92.79 39.59 C100.01 31.28, 107.23 22.97, 126.91 0.34 M97.78 39.95 C108.79 27.28, 119.8 14.61, 132.55 -0.05 M97.78 39.95 C109.46 26.51, 121.14 13.07, 132.55 -0.05 M103.42 39.55 C115.83 25.28, 128.23 11.01, 137.54 0.31 M103.42 39.55 C114.05 27.32, 124.68 15.1, 137.54 0.31 M108.41 39.91 C114.24 33.2, 120.08 26.48, 137.27 6.7 M108.41 39.91 C116.61 30.48, 124.8 21.05, 137.27 6.7 M114.05 39.52 C119.19 33.61, 124.32 27.7, 137.01 13.1 M114.05 39.52 C118.81 34.04, 123.56 28.57, 137.01 13.1 M119.04 39.88 C126.1 31.75, 133.17 23.62, 137.41 18.74 M119.04 39.88 C123.1 35.2, 127.17 30.53, 137.41 18.74 M124.02 40.24 C128.99 34.53, 133.95 28.81, 137.15 25.14 M124.02 40.24 C128.37 35.24, 132.71 30.24, 137.15 25.14 M129.67 39.84 C132.09 37.06, 134.51 34.27, 137.54 30.79 M129.67 39.84 C132.69 36.36, 135.71 32.89, 137.54 30.79" stroke="#82c91e" stroke-width="0.5" fill="none"></path><path d="M0 0 C47.02 0, 94.04 0, 136.67 0 M0 0 C39.95 0, 79.91 0, 136.67 0 M136.67 0 C136.67 7.93, 136.67 15.86, 136.67 37.78 M136.67 0 C136.67 9.75, 136.67 19.5, 136.67 37.78 M136.67 37.78 C85.5 37.78, 34.33 37.78, 0 37.78 M136.67 37.78 C97.93 37.78, 59.2 37.78, 0 37.78 M0 37.78 C0 26.23, 0 14.69, 0 0 M0 37.78 C0 30.21, 0 22.65, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(321.3793920845483 453.45271975418564) rotate(0 27.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">create</text></g><g stroke-linecap="round" transform="translate(109.15720377074649 446.0638393424015) rotate(0 68.33333333333326 18.888905843098996)"><path d="M0 0 C49.19 0, 98.37 0, 136.67 0 M0 0 C38.88 0, 77.76 0, 136.67 0 M136.67 0 C136.67 10.58, 136.67 21.17, 136.67 37.78 M136.67 0 C136.67 11.28, 136.67 22.55, 136.67 37.78 M136.67 37.78 C97.37 37.78, 58.07 37.78, 0 37.78 M136.67 37.78 C107.23 37.78, 77.8 37.78, 0 37.78 M0 37.78 C0 27.01, 0 16.24, 0 0 M0 37.78 C0 24.17, 0 10.57, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(141.37939208454827 452.6193609895372) rotate(0 29 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">cancel</text></g><g transform="translate(62.3386848521759 102.39751456586987) rotate(0 20 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">from</text></g><g transform="translate(211.2023212158124 103.76115092950636) rotate(0 71.5 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">video promotion</text></g></svg> \ No newline at end of file
diff --git a/cf/captcha-payment.txt b/cf/captcha-payment.txt
index 4e24ffd9..7fa02142 100644
--- a/cf/captcha-payment.txt
+++ b/cf/captcha-payment.txt
@@ -6,7 +6,7 @@ Overview:
In many IP reputation systems, CAPTCHAS are used to separate humans from
bots, allowing humans to access resources while blocking automated
attackers. However, especially complex modern Web sites require many
- resources and thus can triger a large number of CAPTCHAS, limiting
+ resources and thus can trigger a large number of CAPTCHAS, limiting
usability. The problem is compounded if users access the Web via
Tor or VPNs, as this means mechanisms to track users cannot be used to
reduce the number of CAPTCHAS.
diff --git a/checklist-demo-upgrade.rst b/checklist-demo-upgrade.rst
deleted file mode 100644
index 5eb00513..00000000
--- a/checklist-demo-upgrade.rst
+++ /dev/null
@@ -1,56 +0,0 @@
-################################
-GNU Taler Demo Upgrade Checklist
-################################
-
-.. |check| raw:: html
-
- <input type="checkbox">
-
-Post-upgrade checks:
-
-- |check| Run ``taler-deployment-arm -I`` to verify that all services are running.
-- |check| Run the headless wallet to check that services are actually working:
-
- .. code-block:: console
-
- $ taler-wallet-cli integrationtest \
- -e https://exchange.demo.taler.net/ \
- -m https://backend.demo.taler.net/ \
- -b https://bank.demo.taler.net \
- -w "KUDOS:10" \
- -s "KUDOS:5"
-
-Basics:
-
-- |check| Visit https://demo.taler.net/ to see if the landing page is displayed correctly
-- |check| Visit the wallet installation page, install the wallet, and see if the presence
- indicator is updated correctly.
-- |check| Visit https://bank.demo.taler.net/, register a new user and withdraw coins into the
- browser wallet.
-
-
-Blog demo:
-
-- |check| Visit https://shop.demo.taler.net/ and purchase an article.
-- |check| Verify that the balance in the wallet was updated correctly.
-- |check| Go back to https://shop.demo.taler.net/ and click on the same article
- link. Verify that the article is shown and **no** repeated payment is
- requested.
-- |check| Open the fulfillment page from the previous step in an anonymous browsing session
- (without the wallet installed) and verify that it requests a payment again.
-- |check| Delete cookies on https://shop.demo.taler.net/ and click on the same article again.
- Verify that the wallet detects that the article has already purchased and successfully
- redirects to the article without spending more money.
-
-Donation demo:
-
-- |check| Make a donation on https://donations.demo.taler.net
-- |check| Make another donation with the same parameters and verify
- that the payment is requested again, instead of showing the previous
- fulfillment page.
-
-Survey/Tipping:
-
-- |check| Visit https://survey.demo.taler.net/ and receive a tip.
-- |check| Verify that the survey stats page (https://survey.demo.taler.net/survey-stats) is working,
- and that the survey reserve has sufficient funds.
diff --git a/checklist-release.rst b/checklist-release.rst
deleted file mode 100644
index 90ca6cb6..00000000
--- a/checklist-release.rst
+++ /dev/null
@@ -1,70 +0,0 @@
-###########################
-GNU Taler Release Checklist
-###########################
-
-
-Release checklists for GNU Taler:
-
-Wallet:
-
-- [ ] build wallet
-- [ ] verify wallet works against 'test.taler.net'
-- [ ] tag repo.
-- [ ] upgrade 'demo.taler.net' to 'test.taler.net'
-- [ ] upload new wallet release to app store
-- [ ] Update bug tracker (mark release, resolved -> closed)
-- [ ] Send announcement to taler@gnu.org
-- [ ] Send announcement to info-gnu@gnu.org (major releases only)
-- [ ] Send announcement to coordinator@translationproject.org
-
-For exchange:
-
-- [ ] check no compiler warnings at "-Wall"
-- [ ] ensure Coverity static analysis passes
-- [ ] make check.
-- [ ] upgrade 'demo.taler.net' to 'test.taler.net'
-- [ ] make dist, make check on result of 'make dist'.
-- [ ] Change version number in configure.ac.
-- [ ] make dist for release.
-- [ ] tag repo.
-- [ ] Upload triplet to ftp-upload.gnu.org/incoming/ftp or /incoming/alpha
-- [ ] Update bug tracker (mark release, resolved -> closed)
-- [ ] Send announcement to taler@gnu.org
-- [ ] Send announcement to info-gnu@gnu.org (major releases only)
-- [ ] Send announcement to coordinator@translationproject.org
-
-For merchant (C backend):
-
-- [ ] check no compiler warnings at "-Wall"
-- [ ] ensure Coverity static analysis passes
-- [ ] make check.
-- [ ] upgrade 'demo.taler.net' to 'test.taler.net'
-- [ ] make dist, make check on result of 'make dist'.
-- [ ] Change version number in configure.ac.
-- [ ] make dist for release.
-- [ ] tag repo.
-- [ ] Upload triplet to ftp-upload.gnu.org/incoming/ftp or /incoming/alpha
-- [ ] Update bug tracker (mark release, resolved -> closed)
-- [ ] Send announcement to taler@gnu.org
-- [ ] Send announcement to info-gnu@gnu.org (major releases only)
-- [ ] Send announcement to coordinator@translationproject.org
-
-For bank:
-
-- TBD
-
-For Python merchant frontend:
-
-- TBD
-
-For PHP merchant frontend:
-
-- TBD
-
-For auditor:
-
-- TBD
-
-For libebics:
-
-- TBD
diff --git a/checklists/checklist-demo-upgrade.rst b/checklists/checklist-demo-upgrade.rst
new file mode 100644
index 00000000..d8724030
--- /dev/null
+++ b/checklists/checklist-demo-upgrade.rst
@@ -0,0 +1,173 @@
+GNU Taler Demo Upgrade Checklist
+--------------------------------
+
+.. |democheck| raw:: html
+
+ <input type="checkbox">
+
+
+Domains
+^^^^^^^
+
+The checklist uses the ``demo.taler.net`` domains. However,
+the same sandcastle demo can also be hosted at other domains.
+The same instructions should apply.
+
+Post-upgrade checks
+^^^^^^^^^^^^^^^^^^^
+
+- |democheck| Run the headless wallet to check that services are actually working:
+
+ .. code-block:: console
+
+ taler-wallet-cli api 'runIntegrationTestV2' '{"exchangeBaseUrl":"https://exchange.demo.taler.net", "corebankApiBaseUrl": "https://bank.demo.taler.net", "merchantBaseUrl": "https://backend.demo.taler.net", "merchantAuthToken":"secret-token:sandbox"}'
+
+
+Wallets
+^^^^^^^
+
+We consider the following published wallets to be "production wallets":
+
+* Browser: Firefox Add-On Store
+* Browser: Chrome Web Store
+* Android: Google Play
+* Android: F-Droid
+* iOS: Apple Store / Testflight
+
+Basics
+^^^^^^
+
+- |democheck| Visit https://demo.taler.net/ to see if the landing page is displayed correctly
+- |democheck| landing language switcher
+- |democheck| Visit the wallet installation page, install the wallet
+- |democheck| see if the wallet presence indicator is updated correctly (in browsers).
+- |democheck| Visit https://bank.demo.taler.net/, register a new user
+- |democheck| bank language switcher
+- |democheck| bank logout
+- |democheck| bank login
+- |democheck| bank-integrated withdraw process, abort in bank
+- |democheck| transaction history: delete pending withdraw
+- |democheck| do bank-integrated withdraw process (5 KUDOS)
+- |democheck| do wallet-initiated withdraw process (5 KUDOS)
+- |democheck| withdraw process of large amount (20 KUDOS) runs into KYC check
+- |democheck| fail KYC check (if possible for the given setup)
+- |democheck| pass KYC check (tests that 2nd attempt is possible)
+- |democheck| withdraw process of very large amount (50 KUDOS) runs into AML check
+- |democheck| visit exchange SPA, create AML officer key
+- |democheck| register AML officer key with offline tool (if possible)
+- |democheck| allow withdraw process blocked on AML to proceed (if possible)
+
+
+Exchange AML SPA
+^^^^^^^^^^^^^^^^
+
+- |democheck| enter non-trivial form, change status to frozen
+- |democheck| check account status in history is now frozen and shows in that category
+- |democheck| enter another form, change status to normal, increase AML threshold
+- |democheck| view forms in history, view previously submitted form
+- |democheck| check account status in history is now normal and shows in that category
+- |democheck| log out
+- |democheck| check log in succeeds with correct password
+- |democheck| check log in fails from different browser with same password
+
+
+Blog demo
+^^^^^^^^^
+
+- |democheck| Visit https://shop.demo.taler.net/
+- |democheck| blog page article list renders
+- |democheck| payment for blog article
+- |democheck| Verify that the balance in the wallet was updated correctly.
+- |democheck| Go back to https://shop.demo.taler.net/ and click on the same article
+ link. Verify that the article is shown and **no** repeated payment is
+ requested.
+- |democheck| Open the fulfillment page from the previous step in an anonymous browsing session
+ (without the wallet installed) and verify that it requests a payment again.
+- |democheck| Delete cookies on https://shop.demo.taler.net/ and click on the same article again.
+ Verify that the wallet detects that the article has already purchased and successfully
+ redirects to the article without spending more money.
+- |democheck| payment for other blog article
+- |democheck| refund of 2nd blog article (button at the end)
+- |democheck| wallet transaction history rendering
+- |democheck| delete refund history entry; check original purchase entry was also deleted
+- |democheck| payment for other blog article
+- |democheck| refund of 3rd blog article (button at the end)
+- |democheck| wallet transaction history rendering
+- |democheck| delete 3rd block purchase history entry; check refund entry was also deleted
+
+
+Donation demo
+^^^^^^^^^^^^^
+
+- |democheck| Reset wallet
+- |democheck| Withdraw age-restricted coins (< 14)
+- |democheck| Try to make a donation on https://donations.demo.taler.net/, fail due to age-restriction
+- |democheck| Withdraw age-restricted coins (>= 14)
+- |democheck| Make a donation on https://donations.demo.taler.net/
+- |democheck| Make another donation with the same parameters and verify
+ that the payment is requested again, instead of showing the previous
+ fulfillment page.
+
+
+Merchant SPA
+^^^^^^^^^^^^
+
+- |democheck| test SPA loads
+- |democheck| try to login with wrong password
+- |democheck| try to login with correct password
+- |democheck| create instance, check default is set to cover (STEFAN) fees
+- |democheck| modify instance
+- |democheck| add bank account
+- |democheck| edit bank account
+- |democheck| remove bank account
+- |democheck| check order creation fails without bank account
+- |democheck| add bank account again
+- |democheck| add product with 1 in stock and preview image
+- |democheck| add "advanced" order with inventory product and a 2 minute wire delay
+- |democheck| claim order, check available stock goes down in inventory
+- |democheck| create 2nd order, check this fails due to missing inventory
+- |democheck| pay for 1st order with wallet
+- |democheck| check transaction history for preview image
+- |democheck| trigger partial refund
+- |democheck| accept refund with wallet
+- |democheck| create template with fixed summary, default editable price
+- |democheck| scan template QR code, edit price and pay
+- |democheck| add TOTP device (using some TOTP app to share secret with)
+- |democheck| edit template to add TOTP device, set price to fixed, summary to be entered
+- |democheck| scan template QR code, edit summary and pay
+- |democheck| check displayed TOTP code matches TOTP app
+- |democheck| do manual wire transfer in bank to establish reserve funding
+- |democheck| check that partially refunded order is marked as awaiting wire transfer
+- |democheck| check bank wired funds to merchant (if needed, wait)
+- |democheck| add bank wire transfer manually to backend
+- |democheck| change settings for merchant to not pay for (STEFAN) fees
+- |democheck| create and pay for another order with 1 minute wire transfer delay
+- |democheck| edit bank account details, adding revenue facade with credentials
+- |democheck| wait and check if wire transfer is automatically imported
+- |democheck| check that orders are marked as completed
+
+
+P2P payments
+^^^^^^^^^^^^
+
+- |democheck| generating push payment (to self is OK)
+- |democheck| accepting push payment (from self is OK)
+- |democheck| generating pull payment (to self is OK)
+- |democheck| accepting pull payment (from self is OK)
+- |democheck| sending money back from wallet to bank account
+- |democheck| wallet transaction history rendering
+- |democheck| delete history entry
+
+
+Shutdown
+^^^^^^^^
+
+- |democheck| create two full wallets, fill one only via (a large) P2P transfer
+- |democheck| revoke highest-value denomination
+- |democheck| spend money in a wallet such that the balance falls below highest denomination value
+- |democheck| revoke all remaining denominations
+- |democheck| fail to spend any more money
+- |democheck| if wallet was filled via p2p payments, wallet asks for target deposit account (exchange going out of business)
+- |democheck| enter bank account (if possible)
+- |democheck| wallet balance goes to zero
+- |democheck| specified bank account receives remaining balance
diff --git a/checklists/checklist-release.rst b/checklists/checklist-release.rst
new file mode 100644
index 00000000..eaefd0b9
--- /dev/null
+++ b/checklists/checklist-release.rst
@@ -0,0 +1,141 @@
+GNU Taler Release Checklist
+---------------------------
+
+.. |releasecheck| raw:: html
+
+ <input type="checkbox">
+
+For exchange:
+
+- |releasecheck| no compiler warnings at "-Wall" with gcc
+- |releasecheck| no compiler warnings at "-Wall" with clang
+- |releasecheck| ensure Coverity static analysis passes
+- |releasecheck| make check.
+- |releasecheck| make dist, make check on result of 'make dist'.
+- |releasecheck| Change version number in configure.ac.
+- |releasecheck| update man pages / info page documentation (prebuilt branch)
+- |releasecheck| make dist for release
+- |releasecheck| verify dist builds from source
+- |releasecheck| upgrade 'demo.taler.net'
+- |releasecheck| run :doc:`demo upgrade checklist </checklists/checklist-demo-upgrade>`
+- |releasecheck| tag repo.
+- |releasecheck| use 'deployment.git/packaging/\*-docker/' to build Debian and Ubuntu packages
+- |releasecheck| upload packages to 'deb.taler.net' (note: only Florian/Christian can sign)
+- |releasecheck| change 'demo.taler.net' deployment to use new tag.
+- |releasecheck| Upload triplet to ftp-upload.gnu.org/incoming/ftp or /incoming/alpha
+
+For merchant (C backend):
+
+- |releasecheck| no compiler warnings at "-Wall" with gcc
+- |releasecheck| no compiler warnings at "-Wall" with clang
+- |releasecheck| ensure Coverity static analysis passes
+- |releasecheck| make check.
+- |releasecheck| make dist, make check on result of 'make dist'.
+- |releasecheck| update SPA (prebuilt branch)
+- |releasecheck| Change version number in configure.ac.
+- |releasecheck| make dist for release.
+- |releasecheck| verify dist builds from source
+- |releasecheck| upgrade 'demo.taler.net'
+- |releasecheck| run :doc:`demo upgrade checklist </checklists/checklist-demo-upgrade>`
+- |releasecheck| tag repo.
+- |releasecheck| use 'deployment.git/packaging/\*-docker/' to build Debian and Ubuntu packages
+- |releasecheck| upload packages to 'deb.taler.net' (note: only Florian/Christian can sign)
+- |releasecheck| change 'demo.taler.net' deployment to use new tag.
+- |releasecheck| Upload triplet to ftp-upload.gnu.org/incoming/ftp or /incoming/alpha
+
+For sync:
+
+- |releasecheck| no compiler warnings at "-Wall" with gcc
+- |releasecheck| no compiler warnings at "-Wall" with clang
+- |releasecheck| ensure Coverity static analysis passes
+- |releasecheck| make check.
+- |releasecheck| make dist, make check on result of 'make dist'.
+- |releasecheck| Change version number in configure.ac.
+- |releasecheck| make dist for release
+- |releasecheck| verify dist builds from source
+- |releasecheck| upgrade 'demo.taler.net'
+- |releasecheck| run :doc:`demo upgrade checklist </checklists/checklist-demo-upgrade>`
+- |releasecheck| tag repo.
+- |releasecheck| use 'deployment.git/packaging/\*-docker/' to build Debian and Ubuntu packages
+- |releasecheck| upload packages to 'deb.taler.net' (note: only Florian/Christian can sign)
+- |releasecheck| change 'demo.taler.net' deployment to use new tag.
+- |releasecheck| Upload triplet to ftp-upload.gnu.org/incoming/ftp or /incoming/alpha
+
+For taler-mdb:
+
+- |releasecheck| no compiler warnings at "-Wall" with gcc
+- |releasecheck| ensure Coverity static analysis passes
+- |releasecheck| Change version number in configure.ac.
+- |releasecheck| make dist for release.
+- |releasecheck| tag repo.
+- |releasecheck| use 'deployment.git/packaging/\*-docker/' to build Debian and Ubuntu packages
+- |releasecheck| upload packages to 'deb.taler.net' (note: only Florian/Christian can sign)
+- |releasecheck| Upload triplet to ftp-upload.gnu.org/incoming/ftp or /incoming/alpha
+
+For taler-twister:
+
+- |releasecheck| no compiler warnings at "-Wall" with gcc
+- |releasecheck| no compiler warnings at "-Wall" with clang
+- |releasecheck| ensure Coverity static analysis passes
+- |releasecheck| make check.
+- |releasecheck| make dist, make check on result of 'make dist'.
+- |releasecheck| Change version number in configure.ac.
+- |releasecheck| make dist for release.
+- |releasecheck| verify dist builds from source
+- |releasecheck| upgrade 'demo.taler.net'
+- |releasecheck| run :doc:`demo upgrade checklist </checklists/checklist-demo-upgrade>`
+- |releasecheck| tag repo.
+- |releasecheck| Upload triplet to ftp-upload.gnu.org/incoming/ftp or /incoming/alpha
+
+For libeufin:
+
+- |releasecheck| update SPA of bank
+- |releasecheck| build libeufin
+- |releasecheck| upgrade 'demo.taler.net'
+- |releasecheck| run :doc:`demo upgrade checklist </checklists/checklist-demo-upgrade>`
+- |releasecheck| make dist for release.
+- |releasecheck| verify dist builds from source
+- |releasecheck| tag repo.
+- |releasecheck| use 'deployment.git/packaging/\*-docker/' to build Debian and Ubuntu packages
+- |releasecheck| upload packages to 'deb.taler.net' (note: only Florian/Christian can sign)
+- |releasecheck| change 'demo.taler.net' deployment to use new tag.
+- |releasecheck| Upload triplet to ftp-upload.gnu.org/incoming/ftp or /incoming/alpha
+
+For Python merchant frontend:
+
+- |releasecheck| upgrade 'demo.taler.net'
+- |releasecheck| run :doc:`demo upgrade checklist </checklists/checklist-demo-upgrade>`
+- |releasecheck| change 'demo.taler.net' deployment to use new tag.
+
+Wallet-core:
+
+- |releasecheck| build wallet
+- |releasecheck| run integration test
+- |releasecheck| make dist for release.
+- |releasecheck| verify dist builds from source
+- |releasecheck| tag repo.
+- |releasecheck| use 'deployment.git/packaging/\*-docker/' to build Debian and Ubuntu packages
+- |releasecheck| upload packages to 'deb.taler.net' (note: only Florian/Christian can sign)
+- |releasecheck| change 'demo.taler.net' deployment to use new tag.
+- |releasecheck| Upload triplet to ftp-upload.gnu.org/incoming/ftp or /incoming/alpha
+
+Android-Wallet:
+
+- |releasecheck| build wallet
+- |releasecheck| run :doc:`demo upgrade checklist </checklists/checklist-demo-upgrade>`
+- |releasecheck| tag repo.
+- |releasecheck| upload new wallet release to app store
+
+Webextension-Wallet:
+
+- |releasecheck| build wallet
+- |releasecheck| run :doc:`demo upgrade checklist </checklists/checklist-demo-upgrade>`
+- |releasecheck| tag repo.
+- |releasecheck| upload new wallet release to app store
+
+Release announcement:
+
+- |releasecheck| Update bug tracker (mark release, resolved -> closed)
+- |releasecheck| Send announcement to taler@gnu.org
+- |releasecheck| Send announcement to info-gnu@gnu.org (major releases only)
+- |releasecheck| Send announcement to coordinator@translationproject.org
diff --git a/checklists/qa-0.10.rst b/checklists/qa-0.10.rst
new file mode 100644
index 00000000..262f44f5
--- /dev/null
+++ b/checklists/qa-0.10.rst
@@ -0,0 +1,233 @@
+Taler 0.9.4 QA Plan
+-------------------
+
+Wallet Platforms
+^^^^^^^^^^^^^^^^
+
+Platforms listed here are the officially supported platforms for this release.
+
+* Overview / Installation Page
+
+ * https://taler.net/en/wallet.html
+
+* Android
+
+ * Google Play: https://play.google.com/store/apps/details?id=net.taler.wallet
+ * F-Droid: https://f-droid.org/en/packages/net.taler.wallet.fdroid/
+ * APK Download: TBD
+
+* Browser
+
+ * Chrome: https://chromewebstore.google.com/detail/gnu-taler-wallet/millncjiddlpgdmkklmhfadpacifaonc
+ * Firefox: https://addons.mozilla.org/en-US/firefox/addon/taler-wallet/
+
+* iOS
+
+
+Running Deployments
+^^^^^^^^^^^^^^^^^^^
+
+These deployments are maintained by us and should work for the release:
+
+* Sandcastle-based:
+
+ * demo.taler.net
+
+ * test.taler.net
+
+* Regio-based:
+
+ * regio-taler.fdold.eu
+
+
+Wallet Flows
+^^^^^^^^^^^^
+
+* Bank-integrated withdrawal
+
+ * webext: "Continue with Mobile Wallet" flow
+
+* Manual withdrawal
+
+ * ``taler://withdraw-exchange`` flow
+
+ * Currency conversion withdrawal
+
+* Peer push payments ("Send Money")
+
+* Peer pull payments ("Receive Money")
+
+* Deposit into bank account
+
+ * Check that deposit arrived
+
+* Payment at merchant
+
+ * on blog merchant
+ * on survey
+ * directly initiated via merchant SPA
+ * webext: "Pay with Mobile Wallet" flow
+
+* Pay templates
+
+ * Payment TOTP codes
+
+* Exchange management
+
+ * Reloading exchange keys
+ * Deleting an exchange
+
+* Offline handling
+
+ * Check error messages for other flows when internet connectivity
+ is bad or device is completely offline.
+
+
+libeufin-bank Flows
+^^^^^^^^^^^^^^^^^^^
+
+* Admin functionality
+
+ * Login
+
+ * Credential change
+
+ * Conversion settings
+
+ * Bank account creation
+
+ * Test transfers
+
+* Normal account functionality
+
+ * Transfers
+
+ * Transfer to the exchange should bounce
+
+ * Withdrawals
+
+ * (conversion-only): Test cash-in
+
+ * (conversion-only): Test cash-out
+
+ * Lower cash-out limit enforced
+
+ * 2FA for withdrawals, cash-out
+
+
+Merchant Backend SPA Flows
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* Instance creation
+
+* Simple bank account setup
+
+* Order creation
+
+ * Pay order (with short wire transfer deadline)
+
+ * Check that money from order arrive at the bank with the right subject
+
+* Extended bank account setup
+
+ * Add Taler Bank Revenue API
+
+ * Check bank transfer list (for wire transfer of previously paid+wired order)
+
+ * Check order payment status goes to "final" automatically
+
+* TOTP Device Management
+
+ * Add device
+
+ * Edit device (set new secret, export new secret as QR code)
+
+ * Delete device
+
+* Templates
+
+ * Add template
+
+ * Edit template
+
+ * Add TOTP device to template
+
+ * Edit TOTP device associated with template
+
+ * Pay template
+
+ * Check TOTP code matches
+
+ * Remove TOTP device from template
+
+ * Delete template
+
+
+
+Regio Deployment
+^^^^^^^^^^^^^^^^
+
+* Deployment Automation (deployment.git/regional-currency)
+
+ * Test with Debian bookworm
+
+ * Test with Ubuntu mantic
+
+ * Check logs for errors
+
+ * Test with telesign (SMS)
+
+ * Set up EBICS integration
+
+ * Check that ToS is configured
+
+* Deployment Functionality
+
+ * All flows of the wallet should work (see ``Wallet Flows`` above)
+
+ * All flows of libeufin-bank should work (see ``libeufin-bank Flows`` above)
+
+ * Merchant backend should work (see ``Merchant Backend SPA Flows`` above)
+
+ * Check logs
+
+
+Android Merchant PoS
+^^^^^^^^^^^^^^^^^^^^
+
+* Test against demo.taler.net
+
+
+Android Cashier App
+^^^^^^^^^^^^^^^^^^^
+
+* Test against demo.taler.net
+
+
+CI
+^^
+
+* https://buildbot.taler.net/#/waterfall
+* CI should pass
+
+
+Debian Repository
+^^^^^^^^^^^^^^^^^
+
+* Debian
+
+ * repo at https://deb.taler.net/apt/debian/
+ * supported codename(s): bookworm
+
+
+* Ubuntu:
+
+ * repo at https://deb.taler.net/apt/ubuntu/
+ * supported codename(s): mantic
+
+
+GNU Release
+^^^^^^^^^^^
+
+* Release announcement
+* FTP upload
diff --git a/checklists/qa-0.9.4.rst b/checklists/qa-0.9.4.rst
new file mode 100644
index 00000000..77e51081
--- /dev/null
+++ b/checklists/qa-0.9.4.rst
@@ -0,0 +1,228 @@
+Taler 0.9.4 QA Plan
+-------------------
+
+Wallet Platforms
+^^^^^^^^^^^^^^^^
+
+Platforms listed here are the officially supported platforms for this release.
+
+* Overview / Installation Page
+
+ * https://taler.net/en/wallet.html
+
+* Android
+
+ * Google Play: https://play.google.com/store/apps/details?id=net.taler.wallet
+ * F-Droid: https://f-droid.org/en/packages/net.taler.wallet.fdroid/
+ * APK Download: TBD
+
+* Browser
+
+ * Chrome: https://chromewebstore.google.com/detail/gnu-taler-wallet/millncjiddlpgdmkklmhfadpacifaonc
+ * Firefox: https://addons.mozilla.org/en-US/firefox/addon/taler-wallet/
+
+* iOS
+
+
+Running Deployments
+^^^^^^^^^^^^^^^^^^^
+
+These deployments are maintained by us and should work for the release:
+
+* Sandcastle-based:
+
+ * demo.taler.net
+
+ * test.taler.net
+
+* Regio-based:
+
+ * regio-taler.fdold.eu
+
+
+Wallet Flows
+^^^^^^^^^^^^
+
+* Bank-integrated withdrawal
+
+ * webext: "Continue with Mobile Wallet" flow
+
+* Manual withdrawal
+
+ * ``taler://withdraw-exchange`` flow
+
+ * Currency conversion withdrawal
+
+* Peer push payments ("Send Money")
+
+* Peer pull payments ("Receive Money")
+
+* Deposit into bank account
+
+ * Check that deposit arrived
+
+* Payment at merchant
+
+ * on blog merchant
+ * on survey
+ * directly initiated via merchant SPA
+ * webext: "Pay with Mobile Wallet" flow
+
+* Pay templates
+
+ * Payment TOTP codes
+
+* Exchange management
+
+ * Reloading exchange keys
+ * Deleting an exchange
+
+
+libeufin-bank Flows
+^^^^^^^^^^^^^^^^^^^
+
+* Admin functionality
+
+ * Login
+
+ * Credential change
+
+ * Conversion settings
+
+ * Bank account creation
+
+ * Test transfers
+
+* Normal account functionality
+
+ * Transfers
+
+ * Transfer to the exchange should bounce
+
+ * Withdrawals
+
+ * (conversion-only): Test cash-in
+
+ * (conversion-only): Test cash-out
+
+ * Lower cash-out limit enforced
+
+ * 2FA for withdrawals, cash-out
+
+
+Merchant Backend SPA Flows
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* Instance creation
+
+* Simple bank account setup
+
+* Order creation
+
+ * Pay order (with short wire transfer deadline)
+
+ * Check that money from order arrive at the bank with the right subject
+
+* Extended bank account setup
+
+ * Add Taler Bank Revenue API
+
+ * Check bank transfer list (for wire transfer of previously paid+wired order)
+
+ * Check order payment status goes to "final" automatically
+
+* TOTP Device Management
+
+ * Add device
+
+ * Edit device (set new secret, export new secret as QR code)
+
+ * Delete device
+
+* Templates
+
+ * Add template
+
+ * Edit template
+
+ * Add TOTP device to template
+
+ * Edit TOTP device associated with template
+
+ * Pay template
+
+ * Check TOTP code matches
+
+ * Remove TOTP device from template
+
+ * Delete template
+
+
+
+Regio Deployment
+^^^^^^^^^^^^^^^^
+
+* Deployment Automation (deployment.git/regional-currency)
+
+ * Test with Debian bookworm
+
+ * Test with Ubuntu mantic
+
+ * Check logs for errors
+
+ * Test with telesign (SMS)
+
+ * Set up EBICS integration
+
+ * Check that ToS is configured
+
+* Deployment Functionality
+
+ * All flows of the wallet should work (see ``Wallet Flows`` above)
+
+ * All flows of libeufin-bank should work (see ``libeufin-bank Flows`` above)
+
+ * Merchant backend should work (see ``Merchant Backend SPA Flows`` above)
+
+ * Check logs
+
+
+Android Merchant PoS
+^^^^^^^^^^^^^^^^^^^^
+
+* Test against demo.taler.net
+
+
+Android Cashier App
+^^^^^^^^^^^^^^^^^^^
+
+* Test against demo.taler.net
+
+
+CI
+^^
+
+* https://buildbot.taler.net/#/waterfall
+* CI should pass
+
+
+Debian Repository
+^^^^^^^^^^^^^^^^^
+
+* Debian
+
+ * repo at https://deb.taler.net/apt/debian/
+ * supported codename(s): bookworm
+
+
+* Ubuntu:
+
+ * repo at https://deb.taler.net/apt/ubuntu/
+ * supported codename(s): mantic
+
+
+GNU Release
+^^^^^^^^^^^
+
+* Release announcement
+* FTP upload
diff --git a/coin.png b/coin.png
deleted file mode 100644
index 5628070d..00000000
--- a/coin.png
+++ /dev/null
Binary files differ
diff --git a/conf.py b/conf.py
index f7aa52e1..43e6ae59 100644
--- a/conf.py
+++ b/conf.py
@@ -1,6 +1,6 @@
"""
This file is part of GNU TALER.
- Copyright (C) 2014, 2015, 2016, 2020, 2021 Taler Systems SA
+ Copyright (C) 2014-2023 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
@@ -17,6 +17,7 @@
@author Benedikt Muller
@author Sree Harsha Totakura
@author Marcello Stanisci
+ @author Christian Grothoff
"""
# -*- coding: utf-8 -*-
#
@@ -35,61 +36,58 @@
import sys
import os
-sys.path.append(os.path.abspath('_exts'))
-
-import taler_sphinx_theme
+sys.path.append(os.path.abspath("_exts"))
# 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('.'))
+# 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'
+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',
+ "ebicsdomain",
+ "typescriptdomain",
+ "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']
+templates_path = ["_templates"]
source_suffix = {
- '.rst': 'restructuredtext',
- '.txt': 'markdown',
- '.md': 'markdown',
+ ".rst": "restructuredtext",
+ ".txt": "markdown",
+ ".md": "markdown",
}
# The encoding of source files.
-#source_encoding = 'utf-8-sig'
+# source_encoding = 'utf-8-sig'
# The master toctree document.
-master_doc = 'index'
+master_doc = "index"
# General information about the project.
-project = u'GNU Taler'
-copyright = u'2014-2021 Taler Systems SA (GPLv3+ or GFDL 1.3+)'
+project = "GNU Taler"
+copyright = "2014-2024 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.8'
+version = "0.10"
# The full version, including alpha/beta/rc tags.
-release = '0.8.2'
+release = "0.10.0"
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -97,133 +95,142 @@ release = '0.8.2'
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
-#today = ''
+# today = ''
# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
+# 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']
+exclude_patterns = [
+ "_build",
+ "_exts",
+ "cf",
+ "prebuilt",
+ "**/README.md",
+ "extract-tsdefs",
+ "frags",
+ "orphaned",
+]
# 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
+# 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
+# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
-#show_authors = False
+# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
+pygments_style = "sphinx"
# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
+# modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
-#keep_warnings = False
+# 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_theme = "sphinx_book_theme"
-html_sidebars = {'**': ['logo-text.html', 'globaltoc.html', 'searchbox.html']}
+#html_sidebars = {"**": ["logo-text.html", "globaltoc.html", "searchbox.html"]}
+#html_sidebars = {"**": ["globaltoc.html", "searchbox.html"]}
html_theme_options = {
# Set the name of the project to appear in the sidebar
- "project_nav_name": "GNU Taler",
- "globaltoc_depth": 4,
- "globaltoc_includehidden": False,
+ "home_page_in_toc": True,
+ "show_navbar_depth": 1,
}
# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
+# html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
-#html_title = None
+html_title = "GNU Taler"
# A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
+html_short_title = "GNU Taler"
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
-#html_logo = None
+html_logo = "images/taler-logo.svg"
# 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
+# 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']
+html_static_path = ["_static"]
+
+# This is a sphinx-book-themes specific parameter to allow for customized css
+html_css_files = ["custom.css"]
# 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 = []
+# 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'
+# 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
+# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
+# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
-#html_additional_pages = {}
+# html_additional_pages = {}
# If false, no module index is generated.
-#html_domain_indices = True
+# html_domain_indices = True
# If false, no index is generated.
-#html_use_index = True
+# html_use_index = True
# If true, the index is split into individual pages for each letter.
-#html_split_index = False
+# html_split_index = False
# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
+# 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
+# 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 = ''
+# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
+# 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': '',
}
@@ -232,123 +239,513 @@ latex_elements = {
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
- ('taler-auditor-manual', 'taler-auditor-manual.tex',
- 'GNU Taler Auditor Manual', 'GNU Taler team', 'manual'),
- ('taler-exchange-manual', 'taler-exchange-manual.tex',
- 'GNU Taler Exchange Manual', 'GNU Taler team', 'manual'),
- ('taler-merchant-manual', 'taler-merchant-manual.tex',
- 'GNU Taler Merchant Manual', 'GNU Taler team', 'manual'),
- ('taler-merchant-pos-terminal', 'taler-merchant-pos-terminal.tex',
- 'GNU Taler Merchant POS Terminal', 'GNU Taler team', 'manual'),
- ('taler-merchant-api-tutorial', 'taler-merchant-api-tutorial.tex',
- 'GNU Taler Merchant API Tutorial', 'GNU Taler team', 'manual'),
- ('taler-bank-manual', 'taler-bank-manual.tex', 'GNU Taler Bank Manual',
- 'GNU Taler team', 'manual'),
- ('taler-backoffice-manual', 'taler-backoffice-manual.tex',
- 'GNU Taler Back Office Manual', 'GNU Taler team', 'manual'),
- ('taler-developer-manual', 'taler-developer-manual.tex', 'GNU Taler Developer Manual',
- 'GNU Taler team', 'manual'),
+ (
+ "taler-auditor-manual",
+ "taler-auditor-manual.tex",
+ "GNU Taler Auditor Manual",
+ "GNU Taler team",
+ "manual",
+ ),
+ (
+ "taler-exchange-manual",
+ "taler-exchange-manual.tex",
+ "GNU Taler Exchange Manual",
+ "GNU Taler team",
+ "manual",
+ ),
+ (
+ "taler-challenger-manual",
+ "taler-challenger-manual.tex",
+ "GNU Taler Challenger Manual",
+ "GNU Taler team",
+ "manual",
+ ),
+ (
+ "taler-merchant-manual",
+ "taler-merchant-manual.tex",
+ "GNU Taler Merchant Manual",
+ "GNU Taler team",
+ "manual",
+ ),
+ (
+ "taler-merchant-pos-terminal",
+ "taler-merchant-pos-terminal.tex",
+ "GNU Taler Merchant POS Terminal",
+ "GNU Taler team",
+ "manual",
+ ),
+ (
+ "taler-merchant-api-tutorial",
+ "taler-merchant-api-tutorial.tex",
+ "GNU Taler Merchant API Tutorial",
+ "GNU Taler team",
+ "manual",
+ ),
+ (
+ "taler-developer-manual",
+ "taler-developer-manual.tex",
+ "GNU Taler Developer Manual",
+ "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
+# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
-#latex_use_parts = False
+# latex_use_parts = False
# If true, show page references after internal links.
-#latex_show_pagerefs = False
+# latex_show_pagerefs = False
# If true, show URL addresses after external links.
-#latex_show_urls = False
+# 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
+# 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 = [
- ("manpages/taler-auditor-exchange.1", "taler-auditor-exchange",
- "add or remove exchange from auditor’s list", "GNU Taler contributors",
- 1),
- ("manpages/taler-auditor-dbinit.1", "taler-auditor-dbinit",
- "setup auditor database", "GNU Taler contributors", 1),
- ("manpages/taler-auditor-sync.1", "taler-auditor-sync",
- "tool to safely synchronize auditor database", "GNU Taler contributors", 1),
- ("manpages/taler-auditor-httpd.1", "taler-auditor-httpd",
- "HTTP server providing a RESTful API to access a Taler auditor",
- "GNU Taler contributors", 1),
- ("manpages/taler-auditor.1", "taler-auditor", "audit exchange",
- "GNU Taler contributors", 1),
- ("manpages/taler-exchange-aggregator.1", "taler-exchange-aggregator",
- "aggregate deposits into wire transfers", "GNU Taler contributors",
- 1),
- ("manpages/taler-exchange-closer.1", "taler-exchange-closer",
- "close idle reserves", "GNU Taler contributors",
- 1),
- ("manpages/taler-exchange-transfer.1", "taler-exchange-transfer",
- "execute wire transfers", "GNU Taler contributors",
- 1),
- ("manpages/taler-exchange-benchmark.1", "taler-exchange-benchmark",
- "measure exchange performance", "GNU Taler contributors", 1),
- ("manpages/taler-exchange-dbinit.1", "taler-exchange-dbinit",
- "initialize Taler exchange database", "GNU Taler contributors", 1),
- ("manpages/taler-exchange-httpd.1", "taler-exchange-httpd",
- "run Taler exchange (with RESTful API)", "GNU Taler contributors", 1),
- ("manpages/taler-auditor-offline.1", "taler-auditor-offline",
- "Taler auditor certifies that it audits a Taler exchange",
- "GNU Taler contributors", 1),
- ("manpages/taler-exchange-offline.1", "taler-exchange-offline",
- "operations using the offline key of a Taler exchange",
- "GNU Taler contributors", 1),
- ("manpages/taler-exchange-wirewatch.1", "taler-exchange-wirewatch",
- "watch for incoming wire transfers", "GNU Taler contributors", 1),
- ("manpages/taler-merchant-benchmark.1", "taler-merchant-benchmark",
- "generate Taler-style benchmarking payments", "GNU Taler contributors",
- 1),
- ("manpages/taler-merchant-dbinit.1", "taler-merchant-dbinit",
- "initialize Taler merchant database", "GNU Taler contributors", 1),
- ("manpages/taler-merchant-httpd.1", "taler-merchant-httpd",
- "run Taler merchant backend (with RESTful API)", "GNU Taler contributors",
- 1),
- ("manpages/taler-merchant-setup-reserve.1", "taler-merchant-setup-reserve",
- "setup reserve for tipping at a Taler merchant backend", "GNU Taler contributors",
- 1),
- ("manpages/taler-exchange-wire-gateway-client.1", "taler-exchange-wire-gateway-client",
- "trigger a transfer at the bank", "GNU Taler contributors", 1),
- ("manpages/taler-config.1", "taler-config", "Taler configuration inspection and editing",
- "GNU Taler contributors", 1),
- ("manpages/taler.conf.5", "taler.conf", "Taler configuration file",
- "GNU Taler contributors", 5),
- ("manpages/taler-exchange-secmod-eddsa.1", "taler-exchange-secmod-eddsa",
- "handle private EDDSA key operations for a Taler exchange",
- "GNU Taler contributors", 1),
- ("manpages/taler-exchange-secmod-rsa.1", "taler-exchange-secmod-rsa",
- "handle private RSA key operations for a Taler exchange",
- "GNU Taler contributors", 1),
- ("manpages/taler-helper-auditor-aggregation.1", "taler-helper-auditor-aggregation",
- "audit Taler exchange aggregation activity", "GNU Taler contributors", 1),
- ("manpages/taler-helper-auditor-coins.1", "taler-helper-auditor-coins",
- "audit Taler coin processing", "GNU Taler contributors", 1),
- ("manpages/taler-helper-auditor-deposits.1", "taler-helper-auditor-deposits",
- "audit Taler exchange database for deposit confirmation consistency",
- "GNU Taler contributors", 1),
- ("manpages/taler-helper-auditor-reserves.1", "taler-helper-auditor-reserves",
- "audit Taler exchange reserve handling", "GNU Taler contributors", 1),
- ("manpages/taler-helper-auditor-wire.1", "taler-helper-auditor-wire",
- "audit exchange database for consistency with the bank's wire transfers",
- "GNU Taler contributors", 1),
+ (
+ "manpages/challenger-config.1",
+ "challenger-config",
+ "manipulate Challenger configuration files",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/challenger-dbinit.1",
+ "challenger-dbinit",
+ "initialize the Challenger database",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/challenger-admin.1",
+ "challenger-admin",
+ "manipulate list of authorized Challenger clients",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/challenger-httpd.1",
+ "challenger-httpd",
+ "provide the Challenger HTTP interface",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/challenger.conf.5",
+ "challenger.conf",
+ "Challenger configuration file",
+ "GNU Taler contributors",
+ 5,
+ ),
+ (
+ "manpages/sync-config.1",
+ "sync-config",
+ "manipulate Sync configuration files",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/sync-dbinit.1",
+ "sync-dbinit",
+ "initialize the Sync database",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/sync-httpd.1",
+ "sync-httpd",
+ "provide the Sync HTTP interface",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/sync.conf.5",
+ "sync.conf",
+ "Sync configuration file",
+ "GNU Taler contributors",
+ 5,
+ ),
+ (
+ "manpages/taler-auditor-exchange.1",
+ "taler-auditor-exchange",
+ "add or remove exchange from auditor’s list",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-auditor-dbinit.1",
+ "taler-auditor-dbinit",
+ "setup auditor database",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-auditor-sync.1",
+ "taler-auditor-sync",
+ "tool to safely synchronize auditor database",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-auditor-httpd.1",
+ "taler-auditor-httpd",
+ "HTTP server providing a RESTful API to access a Taler auditor",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-auditor.1",
+ "taler-auditor",
+ "audit exchange",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-exchange-aggregator.1",
+ "taler-exchange-aggregator",
+ "aggregate deposits into wire transfers",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-terms-generator.1",
+ "taler-terms-generator",
+ "create legal policy documents for services",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-fakebank-run.1",
+ "taler-fakebank-run",
+ "run in-memory bank service for testing and benchmarking",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-exchange-closer.1",
+ "taler-exchange-closer",
+ "close idle reserves",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-exchange-drain.1",
+ "taler-exchange-drain",
+ "drain profits from exchange",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-exchange-kyc-tester.1",
+ "taler-exchange-kyc-tester",
+ "test KYC service integration",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-exchange-expire.1",
+ "taler-exchange-expire",
+ "refund expired purses",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-exchange-router.1",
+ "taler-exchange-router",
+ "route payments to partner exchanges",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-exchange-transfer.1",
+ "taler-exchange-transfer",
+ "execute wire transfers",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-unified-setup.1",
+ "taler-unified-setup",
+ "conveniently start and stop various GNU Taler services",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-exchange-benchmark.1",
+ "taler-exchange-benchmark",
+ "measure exchange performance",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-bank-benchmark.1",
+ "taler-bank-benchmark",
+ "measure bank performance",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-aggregator-benchmark.1",
+ "taler-aggregator-benchmark",
+ "generate database to measure aggregator performance",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-auditor-dbconfig.1",
+ "taler-auditor-dbconfig",
+ "configure Taler auditor database",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-exchange-dbconfig.1",
+ "taler-exchange-dbconfig",
+ "configure Taler exchange database",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-merchant-dbconfig.1",
+ "taler-merchant-dbconfig",
+ "configure Taler merchant database",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/sync-dbconfig.1",
+ "sync-dbconfig",
+ "configure sync database",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/challenger-dbconfig.1",
+ "challenger-dbconfig",
+ "configure challenger database",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-exchange-dbinit.1",
+ "taler-exchange-dbinit",
+ "initialize Taler exchange database",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-exchange-httpd.1",
+ "taler-exchange-httpd",
+ "run Taler exchange (with RESTful API)",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-auditor-offline.1",
+ "taler-auditor-offline",
+ "Taler auditor certifies that it audits a Taler exchange",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-exchange-offline.1",
+ "taler-exchange-offline",
+ "operations using the offline key of a Taler exchange",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-exchange-wirewatch.1",
+ "taler-exchange-wirewatch",
+ "watch for incoming wire transfers",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-merchant-exchange.1",
+ "taler-merchant-exchange",
+ "ask exchange which deposits were aggregated for a particular wire transfer that credited a merchant account",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-merchant-benchmark.1",
+ "taler-merchant-benchmark",
+ "generate Taler-style benchmarking payments",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-mdb.1",
+ "taler-mdb",
+ "operate multi drop bus (MDB) based vending machines with Taler payments",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-merchant-dbinit.1",
+ "taler-merchant-dbinit",
+ "initialize Taler merchant database",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-merchant-passwd.1",
+ "taler-merchant-passwd",
+ "change Taler merchant instance password",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-merchant-httpd.1",
+ "taler-merchant-httpd",
+ "run Taler merchant backend (with RESTful API)",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-merchant-webhook.1",
+ "taler-merchant-webhook",
+ "execute webhooks of the Taler merchant backend (optional service)",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-merchant-wirewatch.1",
+ "taler-merchant-wirewatch",
+ "import credit transactions from a merchant bank account into merchant backend (optional)",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-merchant-depositcheck.1",
+ "taler-merchant-depositcheck",
+ "check status of deposits with exchange",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-exchange-wire-gateway-client.1",
+ "taler-exchange-wire-gateway-client",
+ "trigger a transfer at the bank",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-config.1",
+ "taler-config",
+ "Taler configuration inspection and editing",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-exchange-kyc-aml-pep-trigger.1",
+ "taler-exchange-kyc-aml-pep-trigger",
+ "Taler KYC_AML_TRIGGER example",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler.conf.5",
+ "taler.conf",
+ "Taler configuration file",
+ "GNU Taler contributors",
+ 5,
+ ),
+ (
+ "manpages/taler-exchange-secmod-eddsa.1",
+ "taler-exchange-secmod-eddsa",
+ "handle private EDDSA key operations for a Taler exchange",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-exchange-secmod-cs.1",
+ "taler-exchange-secmod-cs",
+ "handle private CS key operations for a Taler exchange",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-exchange-secmod-rsa.1",
+ "taler-exchange-secmod-rsa",
+ "handle private RSA key operations for a Taler exchange",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-helper-auditor-aggregation.1",
+ "taler-helper-auditor-aggregation",
+ "audit Taler exchange aggregation activity",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-helper-auditor-coins.1",
+ "taler-helper-auditor-coins",
+ "audit Taler coin processing",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-helper-auditor-deposits.1",
+ "taler-helper-auditor-deposits",
+ "audit Taler exchange database for deposit confirmation consistency",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-helper-auditor-purses.1",
+ "taler-helper-auditor-purses",
+ "audit Taler exchange purse handling",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-helper-auditor-reserves.1",
+ "taler-helper-auditor-reserves",
+ "audit Taler exchange reserve handling",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/taler-helper-auditor-wire.1",
+ "taler-helper-auditor-wire",
+ "audit exchange database for consistency with the bank's wire transfers",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/libeufin-nexus.1",
+ "libeufin-nexus",
+ "service to interface to various bank access APIs",
+ "GNU Taler contributors",
+ 1,
+ ),
+ (
+ "manpages/libeufin-nexus.conf.5",
+ "libeufin-nexus.conf",
+ "LibEuFin Nexus configuration file",
+ "GNU Taler contributors",
+ 5,
+ ),
]
# If true, show URL addresses after external links.
-#man_show_urls = False
+# man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
@@ -356,33 +753,92 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
- ("taler-auditor-manual", "taler-auditor", "Taler Auditor Manual",
- "GNU Taler team", "MENU ENTRY", "DESCRIPTION", "CATEGORY"),
- ("taler-exchange-manual", "taler-exchange", "Taler Exchange Manual",
- "GNU Taler team", "MENU ENTRY", "DESCRIPTION", "CATEGORY"),
- ("taler-merchant-manual", "taler-merchant", "Taler Merchant Manual",
- "GNU Taler team", "MENU ENTRY", "DESCRIPTION", "CATEGORY"),
- ("taler-merchant-api-tutorial", "taler-merchant-api-tutorial",
- "Taler Merchant API Tutorial", "GNU Taler team", "MENU ENTRY",
- "DESCRIPTION", "CATEGORY"),
- ("taler-bank-manual", "taler-bank", "Taler Bank Manual", "GNU Taler team",
- "MENU ENTRY", "DESCRIPTION", "CATEGORY"),
- ("taler-developer-manual", "taler-developer-manual", "Taler Developer Manual", "GNU Taler team",
- "MENU ENTRY", "DESCRIPTION", "CATEGORY"),
+ (
+ "taler-auditor-manual",
+ "taler-auditor",
+ "Taler Auditor Manual",
+ "GNU Taler team",
+ "GNU Taler Auditor",
+ "External audit for Taler Exchange operation",
+ "Network applications",
+ ),
+ (
+ "taler-exchange-manual",
+ "taler-exchange",
+ "Taler Exchange Manual",
+ "GNU Taler team",
+ "GNU Taler Exchange",
+ "Taler payment service provider",
+ "Network applications",
+ ),
+ (
+ "taler-challenger-manual",
+ "challenger",
+ "Taler Challenger Manual",
+ "GNU Taler team",
+ "GNU Taler Challenger",
+ "Customer address validation service",
+ "Network applications",
+ ),
+ (
+ "taler-merchant-manual",
+ "taler-merchant",
+ "Taler Merchant Manual",
+ "GNU Taler team",
+ "GNU Taler Merchant",
+ "Backend for merchants accepting Taler payments",
+ "Network applications",
+ ),
+ (
+ "taler-merchant-api-tutorial",
+ "taler-merchant-api-tutorial",
+ "Taler Merchant API Tutorial",
+ "GNU Taler team",
+ "GNU Taler Merchant API",
+ "Tutorial for using the merchant backend API",
+ "Network applications",
+ ),
+ (
+ "taler-developer-manual",
+ "taler-developer-manual",
+ "Taler Developer Manual",
+ "GNU Taler team",
+ "GNU Taler Development",
+ "Manual for GNU Taler contributors",
+ "Network applications",
+ ),
]
# Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
+# texinfo_appendices = []
# If false, no module index is generated.
-#texinfo_domain_indices = True
+# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
+# texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
-#texinfo_no_detailmenu = False
+# 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'
+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/contrib/ci/Containerfile b/contrib/ci/Containerfile
new file mode 100644
index 00000000..023d02de
--- /dev/null
+++ b/contrib/ci/Containerfile
@@ -0,0 +1,23 @@
+FROM docker.io/library/debian:bookworm-slim
+
+ENV DEBIAN_FRONTEND=noninteractive
+
+# Install docs generation utils
+RUN apt-get update -yqq && \
+ apt-get install -yqq --no-install-recommends \
+ make \
+ graphviz \
+ python3-sphinx \
+ python3-recommonmark \
+ python3-texext \
+ python3-sphinx-book-theme \
+ texlive-latex-extra \
+ texlive-fonts-recommended \
+ tex-gyre \
+ dvipng \
+ latexmk \
+ && rm -rf /var/lib/apt/lists/*
+
+WORKDIR /workdir
+
+CMD ["bash", "/workdir/ci/jobs/0-build/job.sh"]
diff --git a/contrib/ci/jobs/0-build/build-docs.sh b/contrib/ci/jobs/0-build/build-docs.sh
new file mode 100755
index 00000000..43152df9
--- /dev/null
+++ b/contrib/ci/jobs/0-build/build-docs.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -exou
+
+make html
+make latexpdf
+
+# Publish to docs.taler.net if on master branch
+if [[ ${CI_GIT_BRANCH} = "master" ]]; then
+ rm -rf /artifacts/docs_build
+
+ mkdir -p /artifacts/docs_build/docs/html/
+ mkdir -p /artifacts/docs_build/docs/pdf/
+
+ cp -r _build/html/* /artifacts/docs_build/docs/html/
+ cp -r _build/latex/*.pdf /artifacts/docs_build/docs/pdf/
+fi
diff --git a/contrib/ci/jobs/0-build/job.sh b/contrib/ci/jobs/0-build/job.sh
new file mode 100755
index 00000000..627aecf0
--- /dev/null
+++ b/contrib/ci/jobs/0-build/job.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+set -exuo pipefail
+
+job_dir=$(dirname "${BASH_SOURCE[0]}")
+
+"${job_dir}"/build-docs.sh
diff --git a/core/api-auditor.rst b/core/api-auditor.rst
index cd0071e5..61e448b8 100644
--- a/core/api-auditor.rst
+++ b/core/api-auditor.rst
@@ -24,6 +24,25 @@ for all details not specified in the individual requests.
The `glossary <https://docs.taler.net/glossary.html#glossary>`_
defines all specific terms used in this section.
+.. contents:: Table of Contents
+ :local:
+
+.. _authentication:
+
+--------------
+Authentication
+--------------
+
+Each auditor instance has separate authentication settings for the private API resources
+of that instance.
+
+Currently, the API supports two main authentication methods:
+
+* ``external``: With this method, no checks are done by the auditor backend.
+ Instead, a reverse proxy / API gateway must do all authentication/authorization checks.
+* ``token``: With this method, the client must provide a ``Authorization: Bearer $TOKEN``
+ header, where ``$TOKEN`` is a secret authentication token configured for the instance which must begin with the RFC 8959 prefix.
+
.. _auditor-version:
-------------------------
@@ -34,9 +53,10 @@ This API is used by merchants to obtain a list of all exchanges audited by
this auditor. This may be required for the merchant to perform the required
know-your-customer (KYC) registration before issuing contracts.
-.. http:get:: /version
+.. http:get:: /config
Get the protocol version and some meta data about the auditor.
+ This specification corresponds to ``current`` protocol being version **1**.
**Response:**
@@ -56,11 +76,19 @@ know-your-customer (KYC) registration before issuing contracts.
// protocol is versioned independently of the exchange's protocol.
version: string;
+ // URN of the implementation (needed to interpret 'revision' in version).
+ // @since v0, may become mandatory in the future.
+ implementation?: string;
+
// Return which currency this auditor is auditing for.
currency: string;
// EdDSA master public key of the auditor.
auditor_public_key: EddsaPublicKey;
+
+ // EdDSA master public key of the exchange.
+ // Added in protocol v1.
+ exchange_master_public_key: EddsaPublicKey;
}
.. note::
@@ -69,58 +97,63 @@ know-your-customer (KYC) registration before issuing contracts.
time of this writing).
-.. _exchange-list:
+.. _exchange_signkeys-list:
------------------------
-Obtaining Exchange List
------------------------
+------------------------------------
+Obtaining Exchange Signing Keys List
+------------------------------------
-This API is used by merchants to obtain a list of all exchanges audited by
-this auditor. This may be required for the merchant to perform the required
-know-your-customer (KYC) registration before issuing contracts.
+This API is used by auditor to obtain a list of all exchanges signing keys to be audited.
-.. http:get:: /exchanges
+.. http:get:: /exchange-sign-keys
- Get a list of all exchanges audited by the auditor.
+ Get a list of all exchange signing keys to be audited by the auditor.
**Response:**
:http:statuscode:`200 OK`:
- The auditor responds with a :ts:type:`ExchangeList` object. This request should
+ The auditor responds with a :ts:type:`ExchangeSignKeysList` object. This request should
virtually always be successful.
**Details:**
- .. ts:def:: ExchangeList
+ .. ts:def:: ExchangeSignKeysList
- interface ExchangeList {
- // Exchanges audited by this auditor.
- exchanges: ExchangeEntry[];
+ interface ExchangeSignKeysList {
+ // Exchange signing keys to be audited by the auditor.
+ exchange-sign-key: ExchangeSignKeyEntry[];
}
- .. ts:def:: ExchangeEntry
+ .. ts:def:: ExchangeSignKeyEntry
- interface ExchangeEntry {
+ interface ExchangeSignKeyEntry {
- // Master public key of the exchange.
- master_pub: EddsaPublicKey;
+ // Public online signing key of the exchange.
+ exchange_pub: EddsaPublicKey;
// Base URL of the exchange.
- exchange_url: string;
+ master_sig: EddsaSignature;
+
+ // Time when online signing key will first be use.
+ ep_valid_from: Timestamp;
+
+ // Time when this online signing key will no longer be used.
+ ep_expire_sign: Timestamp;
+
+ // Time when this online signing key legally expires.
+ ep_expire_legal: Timestamp;
}
.. note::
This API is still experimental (and is not yet implemented at the
- time of this writing). A key open question is whether the auditor
- should sign the information. We might also want to support more
- delta downloads in the future.
+ time of this writing).
.. _deposit-confirmation:
---------------------------------
-Submitting deposit confirmations
---------------------------------
+---------------------
+Deposit Confirmations
+---------------------
Merchants should probabilistically submit some of the deposit
confirmations they receive from the exchange to auditors to ensure
@@ -162,6 +195,9 @@ paid out first.
// Hash over the contract for which this deposit is made.
h_contract_terms: HashCode;
+ // Hash over the extensions.
+ h_extensions: HashCode;
+
// Hash over the wiring information of the merchant.
h_wire: HashCode;
@@ -172,14 +208,19 @@ paid out first.
// request? Zero if refunds are not allowed.
refund_deadline: Timestamp;
+ // By what time does the exchange have to wire the funds?
+ wire_deadline: Timestamp;
+
// Amount to be deposited, excluding fee. Calculated from the
// amount with fee and the fee from the deposit request.
amount_without_fee: Amount;
- // The coin's public key. This is the value that must have been
- // signed (blindly) by the Exchange. The deposit request is to be
- // signed by the corresponding private key (using EdDSA).
- coin_pub: CoinPublicKey;
+ // Array of public keys of the deposited coins.
+ coin_pubs: EddsaPublicKey[];
+
+ // Array of deposit signatures of the deposited coins.
+ // Must have the same length as ``coin_pubs``.
+ coin_sigs: EddsaSignature[];
// The Merchant's public key. Allows the merchant to later refund
// the transaction or to inquire about the wire transfer identifier.
@@ -194,6 +235,7 @@ paid out first.
// Master public key of the exchange corresponding to ``master_sig``.
// Identifies the exchange this is about.
+ // @deprecated since v1 (now ignored, global per auditor)
master_pub: EddsaPublicKey;
// When does the validity of the exchange_pub end?
@@ -215,6 +257,167 @@ paid out first.
time of this writing). A key open question is whether the auditor
should sign the response information.
+This API is used by the auditor to obtain a list of all deposit confirmations that the auditor
+did not receive by the exchange, only by the merchant.
+
+.. http:get:: /deposit-confirmation
+
+ Get a list of all deposit confirmations that were not received by the auditor from the exchange to be manually audited.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The auditor responds with a :ts:type:`DepositConfirmationList` object.
+ :http:statuscode:`204 No Content`:
+ No missing deposit confirmations found.
+
+ **Details:**
+
+ .. ts:def:: DepositConfirmationList
+
+ interface DepositConfirmationList {
+ // Deposit confirmations to be audited.
+ deposit-confirmations: DepositConfirmation[];
+ }
+
+ .. ts:def:: DepositConfirmation
+
+ interface DepositConfirmation {
+
+ // Database row id of entry
+ row_id: Integer;
+
+ // Time when the deposit confirmation confirmation was generated.
+ timestamp: Timestamp;
+
+ // How much time does the merchant have to issue a refund
+ // request? Zero if refunds are not allowed.
+ refund_deadline: Timestamp;
+
+ // By what time does the exchange have to wire the funds?
+ wire_deadline: Timestamp;
+
+ // Amount to be deposited, excluding fee. Calculated from the
+ // amount with fee and the fee from the deposit request.
+ amount_without_fee: Amount;
+ }
+
+ .. note::
+
+ This API is still experimental (and is not yet implemented at the
+ time of this writing).
+
+This API is used by the auditor to delete an audited deposit confirmation.
+
+.. http:delete:: /deposit-confirmation/$SERIAL_ID
+
+ Delete deposit confirmation entry with given serial_id.
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The deposit confirmation was deleted.
+
+ :http:statuscode:`401 Unauthorized`:
+ Unauthorized request.
+
+ :http:statuscode:`404 Not found`:
+ The deposit confirmation was unknown.
+
+ .. note::
+
+ This API is still experimental (and is not yet implemented at the
+ time of this writing).
+
+.. balances-list:
+
+----------------------------------
+Obtaining list of auditor balances
+----------------------------------
+
+This API is used to obtain a list of all the balances that are stored by the auditor.
+
+.. http:get:: /balances
+
+ Get a list of all balances stored by the auditor.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The auditor responds with a :ts:type:`BalanceList` object.
+
+ :http:statuscode:`409 Conflict`:
+ Balance missing or other error occured.
+
+ **Details:**
+
+ .. ts:def:: BalanceList
+
+ interface BalanceList {
+ // Total amount reported
+ auditor_total_reported_balance: Amount;
+
+ // Amount potentially missing
+ auditor_missing_balance: Amount;
+
+ //...
+ }
+
+ .. note::
+
+ This API is still experimental (and is not yet implemented at the
+ time of this writing). The API will be further developed as needed.
+
+.. denominations-pending-list:
+
+---------------------------------------
+Obtaining list of pending denominations
+---------------------------------------
+
+This API is used by the auditor to obtain a list of pending denominations
+
+.. http:get:: /pending-denominations
+
+ Get a list of all pending denominations.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The auditor responds with a :ts:type:`PendingDenominationList` object.
+
+ :http:statuscode:`204 No content`:
+ No pending demoninations found.
+
+ **Details:**
+
+ .. ts:def:: PendingDenominationList
+
+ interface PendingDenominationList {
+ // PendingDenominationList of the auditor.
+ pending_denomination: PendingDenomination[];
+ }
+
+ .. ts:def:: PendingDenomination
+
+ interface PendingDenomination {
+
+ // Balance of denomination.
+ denom_balance: Amount;
+
+ // Amount that was lost due to failures by the exchange.
+ denom_loss: Amount;
+
+ // Amount at risk of loss due to recoup operations.
+ denom_risk: Amount;
+
+ // Amount actually lost due to recoup operations after a revocation.
+ recoup_loss: Amount;
+ }
+
+ .. note::
+
+ This API is still experimental (and is not yet implemented at the
+ time of this writing).
----------
Complaints
diff --git a/core/api-bank-access.rst b/core/api-bank-access.rst
deleted file mode 100644
index ddb2ec80..00000000
--- a/core/api-bank-access.rst
+++ /dev/null
@@ -1,160 +0,0 @@
-..
- 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 Affero 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 Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-
- @author Florian Dold
-
-=====================
-Taler Bank Access API
-=====================
-
-This chapter describes the API that the GNU Taler demonstrator bank offers to access accounts.
-
-This API differs from the "Bank Integration API" in that it provides advanced API access to accounts, as opposed
-to enabling wallets to withdraw with a better user experience ("tight integration").
-
-
-------------------------
-Accounts and Withdrawals
-------------------------
-
-The following endpoints require HTTP "Basic" authentication with the account
-name and account password, at least in the GNU Taler demo bank implementation.
-
-
-.. http:get:: ${BANK_API_BASE_URL}/accounts/${account_name}
-
- Request the current balance of an account.
-
- **Response**
-
- **Details**
-
- .. ts:def:: BankAccountBalanceResponse
-
- interface BankAccountBalanceResponse {
- // Available balance on the account.
- balance: {
- amount: Amount;
- credit_debit_indicator: "credit" | "debit";
- };
- }
-
-
-.. http:POST:: ${BANK_API_BASE_URL}/accounts/${account_name}/withdrawals
-
- Create a withdrawal operation, resulting in a ``taler://withdraw`` URI.
-
- **Request**
-
- .. ts:def:: BankAccountCreateWithdrawalRequest
-
- interface BankAccountCreateWithdrawalRequest {
- // Amount to withdraw.
- amount: Amount;
- }
-
- **Response**
-
- .. ts:def:: BankAccountCreateWithdrawalResponse
-
- interface BankAccountCreateWithdrawalResponse {
- // ID of the withdrawal, can be used to view/modify the withdrawal operation.
- withdrawal_id: string;
-
- // URI that can be passed to the wallet to initiate the withdrawal.
- taler_withdraw_uri: string;
- }
-
-
-.. http:GET:: ${BANK_API_BASE_URL}/accounts/${account_name}/withdrawals/${withdrawal_id}
-
- Query the status of a withdrawal operation.
-
- **Response**
-
- **Details**
-
- .. ts:def:: BankAccountGetWithdrawalResponse
-
- interface BankAccountGetWithdrawalResponse {
- // Amount that will be withdrawn with this withdrawal operation.
- amount: Amount;
-
- // Was the withdrawal aborted?
- aborted: boolean;
-
- // Has the withdrawal been confirmed by the bank?
- // The wire transfer for a withdrawal is only executed once
- // both ``confirmation_done`` is ``true`` and ``selection_done`` is ``true``.
- confirmation_done: boolean;
-
- // Did the wallet select reserve details?
- selection_done: boolean;
-
- // Reserve public key selected by the exchange,
- // only non-null if ``selection_done`` is ``true``.
- selected_reserve_pub: string | null;
-
- // Exchange account selected by the exchange,
- // only non-null if ``selection_done`` is ``true``.
- selected_exchange_account: string | null;
- }
-
-
-.. http:POST:: ${BANK_API_BASE_URL}/accounts/${account_name}/withdrawals/${withdrawal_id}/abort
-
- Abort a withdrawal operation. Has no effect on an already aborted withdrawal operation.
-
- :http:statuscode:`200 OK`: The withdrawal operation has been aborted. The response is an empty JSON object.
- :http:statuscode:`409 Conflict`: The reserve operation has been confirmed previously and can't be aborted.
-
-
-.. http:POST:: ${BANK_API_BASE_URL}/accounts/${account_name}/withdrawals/${withdrawal_id}/confirm
-
- Confirm a withdrawal operation. Has no effect on an already confirmed withdrawal operation.
-
- **Response**
-
- :http:statuscode:`200 OK`: The withdrawal operation has been confirmed. The response is an empty JSON object.
- :http:statuscode:`409 Conflict`: The reserve operation has been aborted previously and can't be confirmed.
-
-
-
-
-----------------------
-Registration (Testing)
-----------------------
-
-
-.. http:POST:: ${BANK_API_BASE_URL}/testing/register
-
- Create a new bank account. This endpoint should be disabled for most deployments, but is useful
- for automated testing / integration tests.
-
- **Request**
-
- .. ts:def:: BankRegistrationRequest
-
- interface BankRegistrationRequest {
- username: string;
-
- password: string;
- }
-
-
- **Response**
-
- :http:statuscode:`200 OK`: Registration was successful.
diff --git a/core/api-bank-conversion-info.rst b/core/api-bank-conversion-info.rst
new file mode 100644
index 00000000..322e9403
--- /dev/null
+++ b/core/api-bank-conversion-info.rst
@@ -0,0 +1,223 @@
+..
+ This file is part of GNU TALER.
+
+ Copyright (C) 2014-2023 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Marcello Stanisci
+ @author Christian Grothoff
+ @author Florian Dold
+
+=========================
+Taler Conversion Info API
+=========================
+
+This chapter describes the conversion info API. The conversion info API
+is used by wallets for withdrawals that involve a currency conversion.
+
+
+.. contents:: Table of Contents
+
+.. http:get:: /config
+
+ Get configuration information about the bank.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ Response is a `ConversionConfig`.
+ :http:statuscode:`501 Not implemented`:
+ This server does not support conversion, client should check config response.
+
+ **Details:**
+
+ .. ts:def:: ConversionConfig
+
+ interface ConversionConfig {
+ // libtool-style representation of the Bank protocol version, see
+ // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
+ // The format is "current:revision:age".
+ version: string;
+
+ // Name of the API.
+ name: "taler-conversion-info";
+
+ // URN of the implementation (needed to interpret 'revision' in version).
+ // @since v4, may become mandatory in the future.
+ implementation?: string;
+
+ // Currency used by this bank.
+ regional_currency: string;
+
+ // How the bank SPA should render this currency.
+ regional_currency_specification: CurrencySpecification;
+
+ // External currency used during conversion.
+ fiat_currency: string;
+
+ // How the bank SPA should render this currency.
+ fiat_currency_specification: CurrencySpecification;
+
+ // Additional information on conversion rates.
+ // Those informations should never be used to perform conversions,
+ // use /cashin-rate or /cashout-rate instead.
+ // Conversion rates can change at any time. Clients must deal with
+ // any resulting errors and call /cashin-rate or /cashout-rate again
+ // to use the new rates.
+ conversion_rate: ConversionRate;
+ }
+
+
+.. http:get:: /cashin-rate
+
+ This public endpoint allows clients to calculate
+ the exchange rate between the regional currency
+ and the fiat currency of the banking system.
+
+ This endpoint shows how the bank would apply the cash-in
+ ratio and fee to one input amount. Typically, wallets would
+ request this endpoint before creating withdrawals that involve
+ a currency conversion.
+
+ **Request:**
+
+ :query amount_debit: this is the amount that the user will get
+ deducted from their fiat bank account.
+
+ or
+
+ :query amount_credit: this is the amount that the user will receive
+ in their regional bank account.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ Response is a `CashinConversionResponse`.
+ :http:statuscode:`400 Bad request`:
+ * ``TALER_EC_GENERIC_PARAMETER_MISSING`` : none of the parameters have been provided.
+ * ``TALER_EC_GENERIC_PARAMETER_MALFORMED`` : both of the parameters have been provided or one of them is not a valid Taler amount.
+ * ``TALER_EC_GENERIC_CURRENCY_MISMATCH`` : the parameter is in the wrong currency.
+ :http:statuscode:`409 Conflict`:
+ The amount is too small to be converted, either because it produces produce an amount less than zero, or because the server requires a higher minimum amount than that supplied.
+ :http:statuscode:`501 Not implemented`:
+ This server does not support conversion, client should check config response.
+
+ **Details:**
+
+ .. ts:def:: CashinConversionResponse
+
+ interface CashinConversionResponse {
+ // Amount that the user will get deducted from their fiat
+ // bank account, according to the 'amount_credit' value.
+ amount_debit: Amount;
+ // Amount that the user will receive in their regional
+ // bank account, according to 'amount_debit'.
+ amount_credit: Amount;
+ }
+
+.. http:get:: /cashout-rate
+
+ This public endpoint allows clients to calculate
+ the exchange rate between the regional currency
+ and the fiat currency of the banking system.
+
+ This endpoint shows how the bank would apply the cash-out
+ ratio and fee to one input amount. Typically, frontends
+ ask this endpoint before creating cash-in operations.
+
+ **Request:**
+
+ :query amount_debit: this is the amount that the user will get
+ deducted from their regional bank account.
+
+ or
+
+ :query amount_credit: this is the amount that the user will receive
+ in their fiat bank account.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ Response is a `CashoutConversionResponse`.
+ :http:statuscode:`400 Bad request`:
+ * ``TALER_EC_GENERIC_PARAMETER_MISSING`` : none of the parameters have been provided.
+ * ``TALER_EC_GENERIC_PARAMETER_MALFORMED`` : both of the parameters have been provided or one of them is not a valid Taler amount.
+ * ``TALER_EC_GENERIC_CURRENCY_MISMATCH`` : the parameter is in the wrong currency.
+ :http:statuscode:`409 Conflict`:
+ The amount is too small to be converted, either because it produces produce an amount less than zero, or because the server requires a higher minimum amount than that supplied.
+ :http:statuscode:`501 Not implemented`:
+ This server does not support conversion, client should check config response.
+
+ **Details:**
+
+ .. ts:def:: CashoutConversionResponse
+
+ interface CashoutConversionResponse {
+ // Amount that the user will get deducted from their regional
+ // bank account, according to the 'amount_credit' value.
+ amount_debit: Amount;
+ // Amount that the user will receive in their fiat
+ // bank account, according to 'amount_debit'.
+ amount_credit: Amount;
+ }
+
+.. http:post:: /conversion-rate
+
+ This endpoint allows the administrator to update
+ the exchange rate between the regional currency
+ and the fiat currency of the banking system.
+
+ **Request:**
+
+ .. ts:def:: ConversionRate
+
+ interface ConversionRate {
+ // Exchange rate to buy regional currency from fiat
+ cashin_ratio: DecimalNumber;
+
+ // Regional amount fee to subtract after applying the cashin ratio.
+ cashin_fee: Amount;
+
+ // Minimum fiat amount authorised for cashin before conversion
+ cashin_min_amount: Amount;
+
+ // Smallest possible regional amount, converted amount is rounded to this amount
+ cashin_tiny_amount: Amount;
+
+ // Rounding mode used during cashin conversion
+ cashin_rounding_mode: "zero" | "up" | "nearest";
+
+ // Exchange rate to sell regional currency for fiat
+ cashout_ratio: DecimalNumber;
+
+ // Fiat amount fee to subtract after applying the cashout ratio.
+ cashout_fee: Amount;
+
+ // Minimum regional amount authorised for cashout before conversion
+ cashout_min_amount: Amount;
+
+ // Smallest possible fiat amount, converted amount is rounded to this amount
+ cashout_tiny_amount: Amount;
+
+ // Rounding mode used during cashout conversion
+ cashout_rounding_mode: "zero" | "up" | "nearest";
+ }
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ Operation successful.
+ :http:statuscode:`401 Unauthorized`:
+ Invalid credentials or missing rights.
+ :http:statuscode:`501 Not implemented`:
+ This server does not support conversion, client should check config response.
diff --git a/core/api-bank-integration.rst b/core/api-bank-integration.rst
index 298e3d75..ed4d8de0 100644
--- a/core/api-bank-integration.rst
+++ b/core/api-bank-integration.rst
@@ -1,7 +1,7 @@
..
This file is part of GNU TALER.
- Copyright (C) 2014-2020 Taler Systems SA
+ Copyright (C) 2014-2023 Taler Systems SA
TALER 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
@@ -28,31 +28,37 @@ to tightly integrate with GNU Taler.
.. http:get:: /config
- Get configuration information about the bank.
-
- **Request:**
+ Return the protocol version and configuration information about the bank.
+ This specification corresponds to ``current`` protocol being version **2**.
**Response:**
:http:statuscode:`200 OK`:
- The exchange responds with a `BankVersion` object. This request should
+ The exchange responds with a `IntegrationConfig` object. This request should
virtually always be successful.
**Details:**
- .. ts:def:: BankVersion
+ .. ts:def:: IntegrationConfig
+
+ interface IntegrationConfig {
+ // Name of the API.
+ name: "taler-bank-integration";
- interface BankVersion {
// libtool-style representation of the Bank protocol version, see
// https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
// The format is "current:revision:age".
version: string;
+ // URN of the implementation (needed to interpret 'revision' in version).
+ // @since v2, may become mandatory in the future.
+ implementation?: string;
+
// Currency used by this bank.
currency: string;
- // Name of the API.
- name: "taler-bank-integration";
+ // How the bank SPA should render this currency.
+ currency_specification: CurrencySpecification;
}
@@ -63,38 +69,42 @@ Withdrawing
Withdrawals with a Taler-integrated bank are based on withdrawal operations.
Some user interaction (on the bank's website or a Taler-enabled ATM) creates a
withdrawal operation record in the bank's database. The wallet can use a unique identifier
-for the withdrawal operation (the ``wopid``) to interact with the withdrawal operation.
+for the withdrawal operation (the ``WITHDRAWAL_ID``) to interact with the withdrawal operation.
-.. http:get:: ${BANK_API_BASE_URL}/withdrawal-operation/${wopid}
+.. http:get:: /withdrawal-operation/$WITHDRAWAL_ID
- Query information about a withdrawal operation, identified by the ``wopid``.
+ Query information about a withdrawal operation, identified by the ``WITHDRAWAL_ID``.
- **Request**
+ **Request:**
:query long_poll_ms:
*Optional.* If specified, the bank will wait up to ``long_poll_ms``
- milliseconds for completion of the transfer before sending the HTTP
+ milliseconds for operationt state to be different from ``old_state`` before sending the HTTP
response. A client must never rely on this behavior, as the bank may
return a response immediately.
+ :query old_state:
+ *Optional.* Default to "pending".
- **Response**
+ **Response:**
:http:statuscode:`200 OK`:
The withdrawal operation is known to the bank, and details are given
in the `BankWithdrawalOperationStatus` response body.
+ :http:statuscode:`404 Not found`:
+ The operation was not found
+ **Details:**
.. ts:def:: BankWithdrawalOperationStatus
export class BankWithdrawalOperationStatus {
- // Has the wallet selected parameters for the withdrawal operation
- // (exchange and reserve public key) and successfully sent it
- // to the bank?
- selection_done: boolean;
-
- // The transfer has been confirmed and registered by the bank.
- // Does not guarantee that the funds have arrived at the exchange already.
- transfer_done: boolean;
+ // Current status of the operation
+ // pending: the operation is pending parameters selection (exchange and reserve public key)
+ // selected: the operations has been selected and is pending confirmation
+ // aborted: the operation has been aborted
+ // confirmed: the transfer has been confirmed and registered by the bank
+ // @since v1
+ status: "pending" | "selected" | "aborted" | "confirmed";
// Amount that will be withdrawn with this operation
// (raw amount without fee considerations).
@@ -109,51 +119,152 @@ for the withdrawal operation (the ``wopid``) to interact with the withdrawal ope
// URL that the user needs to navigate to in order to
// complete some final confirmation (e.g. 2FA).
+ // Only applicable when ``status`` is ``selected`` or ``pending``.
+ // It may contain withdrawal operation id
confirm_transfer_url?: string;
// Wire transfer types supported by the bank.
wire_types: string[];
- }
-.. http:post:: ${BANK_API_BASE_URL}/withdrawal-operation/${wopid}
+ // Reserve public key selected by the exchange,
+ // only non-null if ``status`` is ``selected`` or ``confirmed``.
+ // @since v1
+ selected_reserve_pub?: EddsaPublicKey;
- **Request** The body of this request must have the format of a `BankWithdrawalOperationPostRequest`.
+ // Exchange account selected by the wallet
+ // only non-null if ``status`` is ``selected`` or ``confirmed``.
+ // @since v1
+ selected_exchange_account?: string;
- **Response**
+ // @deprecated since v1, use ``status`` instead
+ // Indicates whether the withdrawal was aborted.
+ aborted: boolean;
- :http:statuscode:`200 OK`:
- The bank has accepted the withdrawal operation parameters chosen by the wallet.
- The response is a `BankWithdrawalOperationPostResponse`.
- :http:statuscode:`404 Not found`:
- The bank does not know about a withdrawal operation with the specified ``wopid``.
+ // @deprecated since v1, use ``status`` instead
+ // Has the wallet selected parameters for the withdrawal operation
+ // (exchange and reserve public key) and successfully sent it
+ // to the bank?
+ selection_done: boolean;
- **Details**
+ // @deprecated since v1, use ``status`` instead
+ // The transfer has been confirmed and registered by the bank.
+ // Does not guarantee that the funds have arrived at the exchange already.
+ transfer_done: boolean;
+ }
+
+
+.. http:post:: /withdrawal-operation/$WITHDRAWAL_ID
+
+ **Request:**
.. ts:def:: BankWithdrawalOperationPostRequest
interface BankWithdrawalOperationPostRequest {
-
// Reserve public key.
- reserve_pub: string;
+ reserve_pub: EddsaPublicKey;
- // Exchange bank details specified in the ``payto``
- // format. NOTE: this field is optional, therefore
- // the bank will initiate the withdrawal with the
- // default exchange, if not given.
- exchange_wire_details: string;
+ // Payto address of the exchange selected for the withdrawal.
+ selected_exchange?: string;
}
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The bank has accepted the withdrawal operation parameters chosen by the wallet.
+ The response is a `BankWithdrawalOperationPostResponse`.
+ :http:statuscode:`404 Not found`:
+ The bank does not know about a withdrawal operation with the specified ``WITHDRAWAL_ID``.
+ :http:statuscode:`409 Conflict`:
+ * ``TALER_EC_BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT`` :
+ The wallet selected a different exchange or reserve public key under the same withdrawal ID.
+ * ``TALER_EC_BANK_DUPLICATE_RESERVE_PUB_SUBJECT`` : the reserve public key is already used.
+ * ``TALER_EC_BANK_UNKNOWN_ACCOUNT`` : the selected exchange account was not found.
+ * ``TALER_EC_BANK_ACCOUNT_IS_NOT_EXCHANGE`` : the selected account is not an exchange.
+
+ **Details:**
+
.. ts:def:: BankWithdrawalOperationPostResponse
interface BankWithdrawalOperationPostResponse {
-
- // The transfer has been confirmed and registered by the bank.
- // Does not guarantee that the funds have arrived at the exchange already.
- transfer_done: boolean;
+ // Current status of the operation
+ // pending: the operation is pending parameters selection (exchange and reserve public key)
+ // selected: the operations has been selected and is pending confirmation
+ // aborted: the operation has been aborted
+ // confirmed: the transfer has been confirmed and registered by the bank
+ status: "selected" | "aborted" | "confirmed";
// URL that the user needs to navigate to in order to
// complete some final confirmation (e.g. 2FA).
//
- // Only applicable when ``transfer_done`` is ``false``.
+ // Only applicable when ``status`` is ``selected`` or ``pending``.
+ // It may contain withdrawal operation id
confirm_transfer_url?: string;
+ // The transfer has been confirmed and registered by the bank.
+ // Does not guarantee that the funds have arrived at the exchange already.
+ transfer_done: boolean;
+ }
+
+.. http:post:: /withdrawal-operation/$WITHDRAWAL_ID/confirm
+
+ Since protocol vC2EC
+
+ Allows a provider to notify the Bank about the payment. This will trigger a payment
+ attestation at the provider, which eventually confirms the payment and allows the
+ withdrawal. The API is idempotent, meaning sending a payment
+ notification for the same ``WITHDRAWAL_ID`` return successfuly but not change anything.
+
+ Attention: A bank shall **never** just accept the payment directly but instead attest
+ the payment using provider specific attestation logic!
+
+ **Request:**
+
+ .. ts:def:: BankWithdrawalConfirmationRequest
+
+ interface WithdrawalConfirmationRequest {
+ // The provider specific transaction identifier.
+ // This identifier is used by the bank to attest the
+ // payment at the providers backend.
+ provider_transaction_id: string;
+
+ // An identifier, which identifies the device
+ // processing the payment for the withdrawal
+ // triggering the confirmation (e.g. Terminal
+ // or ATM). This is needed to link the withdrawal
+ // to a terminal owned by a specific provider.
+ // This will decide about how the withdrawal
+ // is attested. The device must be known to
+ // the exchange and be somehow registered.
+ terminal_id: number;
+
+ // The amount to withdraw. Fees are to be sent in the
+ // separate field 'fees' and not included in the amount.
+ amount: Amount;
+
+ // The fees, the customer paid at the providers facility.
+ card_fees: Amount;
}
+
+ **Response**
+
+ :http:statuscode:`204 No content`:
+ The payment notification was processed successfully.
+ :http:statuscode:`404 Not found`:
+ The withdrawal operation was not found.
+ :http:statuscode:`409 Conflict`:
+ The withdrawal operation has been aborted previously and can't be aborted
+
+
+.. http:post:: /withdrawal-operation/$WITHDRAWAL_ID/abort
+
+ Aborts ``WITHDRAWAL_ID`` operation. Has no effect on an already aborted
+ operation.
+ Since protocol v2.
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The withdrawal operation has been aborted.
+ :http:statuscode:`404 Not found`:
+ The withdrawal operation was not found.
+ :http:statuscode:`409 Conflict`:
+ The withdrawal operation has been confirmed previously and can't be aborted.
diff --git a/core/api-bank-merchant.rst b/core/api-bank-revenue.rst
index 2c8f1934..98b38113 100644
--- a/core/api-bank-merchant.rst
+++ b/core/api-bank-revenue.rst
@@ -1,6 +1,6 @@
..
This file is part of GNU TALER.
- Copyright (C) 2021 Taler Systems SA
+ Copyright (C) 2021-2023 Taler Systems SA
TALER 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
@@ -13,15 +13,46 @@
You should have received a copy of the GNU Affero General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-============================
-Taler Bank Merchant HTTP API
-============================
+.. _taler-bank-merchant-http-api:
-This section describes an API offered by the Taler wire gateway. The API is
-used by the merchant to query for incoming transactions.
+===========================
+Taler Bank Revenue HTTP API
+===========================
-This API is TO BE implemented by the Taler Demo Bank, as well as by
-LibEuFin (work in progress).
+This section describes an API offered by libeufin-nexus and libeufin-bank. The API is
+used by the merchant (or other parties) to query for incoming transactions to their account.
+
+.. http:get:: /config
+
+ Return the protocol version and configuration information about the bank.
+ This specification corresponds to ``current`` protocol being version **0**.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The exchange responds with a `RevenueConfig` object. This request should
+ virtually always be successful.
+
+ **Details:**
+
+ .. ts:def:: RevenueConfig
+
+ interface RevenueConfig {
+ // Name of the API.
+ name: "taler-revenue";
+
+ // libtool-style representation of the Bank protocol version, see
+ // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
+ // The format is "current:revision:age".
+ version: string;
+
+ // Currency used by this gateway.
+ currency: string;
+
+ // URN of the implementation (needed to interpret 'revision' in version).
+ // @since v0, may become mandatory in the future.
+ implementation?: string;
+ }
--------------
@@ -35,17 +66,11 @@ The bank library authenticates requests to the bank merchant API using
Querying the transaction history
--------------------------------
+.. http:get:: /history
-.. http:get:: ${BASE_URL}/history
-
- Return a list of transactions made from an exchange to the merchant.
+ Return a list of transactions made to an account.
- Incoming transactions must contain a valid wire transfer identifier and
- exchange base URL. If a bank transaction does not conform to the right
- syntax, the wire gateway must not report it to the merchant via this
- endpoint.
-
- The bank account of the merchant is determined via the base URL and/or the
+ The bank account is determined via the base URL and/or the
user name in the ``Authorization`` header. In fact, the transaction history
might come from a "virtual" account, where multiple real bank accounts are
merged into one history.
@@ -69,7 +94,7 @@ Querying the transaction history
* A value that is **smaller** than all other row IDs if *delta* is **positive**.
* A value that is **larger** than all other row IDs if *delta* is **negative**.
- **Request**
+ **Request:**
:query start: *Optional.*
Row identifier to explicitly set the *starting point* of the query.
@@ -82,26 +107,34 @@ Querying the transaction history
the bank may return a response immediately or after waiting only a fraction
of ``long_poll_ms``.
- **Response**
+ **Response:**
- :http:statuscode:`200 OK`: JSON object of type `MerchantIncomingHistory`.
- :http:statuscode:`400 Bad request`: Request malformed. The bank replies with an `ErrorDetail` object.
- :http:statuscode:`401 Unauthorized`: Authentication failed, likely the credentials are wrong.
- :http:statuscode:`404 Not found`: The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object.
+ :http:statuscode:`200 OK`:
+ JSON object of type `RevenueIncomingHistory`.
+ :http:statuscode:`400 Bad request`:
+ Request malformed. The bank replies with an `ErrorDetail` object.
+ :http:statuscode:`401 Unauthorized`:
+ Authentication failed, likely the credentials are wrong.
+ :http:statuscode:`404 Not found`:
+ The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object.
- .. ts:def:: MerchantIncomingHistory
+ **Details:**
- interface MerchantIncomingHistory {
+ .. ts:def:: RevenueIncomingHistory
+ interface RevenueIncomingHistory {
// Array of incoming transactions.
- incoming_transactions : MerchantIncomingBankTransaction[];
+ incoming_transactions : RevenueIncomingBankTransaction[];
+ // Payto URI to identify the receiver of funds.
+ // Credit account is shared by all incoming transactions
+ // as per the nature of the request.
+ credit_account: string;
}
- .. ts:def:: MerchantIncomingBankTransaction
-
- interface MerchantIncomingBankTransaction {
+ .. ts:def:: RevenueIncomingBankTransaction
+ interface RevenueIncomingBankTransaction {
// Opaque identifier of the returned record.
row_id: SafeUint64;
@@ -114,9 +147,6 @@ Querying the transaction history
// Payto URI to identify the sender of funds.
debit_account: string;
- // Base URL of the exchange where the transfer originated form.
- exchange_url: string;
-
- // The wire transfer identifier.
- wtid: WireTransferIdentifierRawP;
+ // The wire transfer subject.
+ subject: string;
}
diff --git a/core/api-wire.rst b/core/api-bank-wire.rst
index 63373f68..a76f5195 100644
--- a/core/api-wire.rst
+++ b/core/api-bank-wire.rst
@@ -1,6 +1,6 @@
..
This file is part of GNU TALER.
- Copyright (C) 2019-2021 Taler Systems SA
+ Copyright (C) 2019-2023 Taler Systems SA
TALER 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
@@ -13,6 +13,8 @@
You should have received a copy of the GNU Affero General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+.. _taler-wire-gateway-http-api:
+
===========================
Taler Wire Gateway HTTP API
===========================
@@ -24,6 +26,37 @@ well as by the auditor to query incoming and outgoing transactions.
This API is currently implemented by the Taler Demo Bank, as well as by
LibEuFin (work in progress).
+.. http:get:: /config
+
+ Return the protocol version and configuration information about the bank.
+ This specification corresponds to ``current`` protocol being version **0**.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The exchange responds with a `WireConfig` object. This request should
+ virtually always be successful.
+
+ **Details:**
+
+ .. ts:def:: WireConfig
+
+ interface WireConfig {
+ // Name of the API.
+ name: "taler-wire-gateway";
+
+ // libtool-style representation of the Bank protocol version, see
+ // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
+ // The format is "current:revision:age".
+ version: string;
+
+ // Currency used by this gateway.
+ currency: string;
+
+ // URN of the implementation (needed to interpret 'revision' in version).
+ // @since v0, may become mandatory in the future.
+ implementation?: string;
+ }
--------------
Authentication
@@ -36,7 +69,7 @@ The bank library authenticates requests to the wire gateway via
Making Transactions
-------------------
-.. http:post:: ${BASE_URL}/transfer
+.. http:post:: /transfer
This API allows the exchange to make a transaction, typically to a merchant. The bank account
of the exchange is not included in the request, but instead derived from the user name in the
@@ -45,7 +78,31 @@ Making Transactions
To make the API idempotent, the client must include a nonce. Requests with the same nonce
are rejected unless the request is the same.
- **Request:** The body of this request must have the format of a `TransferRequest`.
+ **Request:**
+
+ .. ts:def:: TransferRequest
+
+ interface TransferRequest {
+ // Nonce to make the request idempotent. Requests with the same
+ // ``request_uid`` that differ in any of the other fields
+ // are rejected.
+ request_uid: HashCode;
+
+ // Amount to transfer.
+ amount: Amount;
+
+ // Base URL of the exchange. Shall be included by the bank gateway
+ // in the appropriate section of the wire transfer details.
+ exchange_base_url: string;
+
+ // Wire transfer identifier chosen by the exchange,
+ // used by the merchant to identify the Taler order(s)
+ // associated with this wire transfer.
+ wtid: ShortHashCode;
+
+ // The recipient's account identifier as a payto URI.
+ credit_account: string;
+ }
**Response:**
@@ -59,7 +116,7 @@ Making Transactions
:http:statuscode:`404 Not found`:
The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object.
:http:statuscode:`409 Conflict`:
- A transaction with the same ``transaction_uid`` but different transaction details
+ A transaction with the same ``request_uid`` but different transaction details
has been submitted before.
**Details:**
@@ -67,7 +124,6 @@ Making Transactions
.. ts:def:: TransferResponse
interface TransferResponse {
-
// Timestamp that indicates when the wire transfer will be executed.
// In cases where the wire transfer gateway is unable to know when
// the wire transfer will be executed, the time at which the request
@@ -82,37 +138,12 @@ Making Transactions
}
- .. ts:def:: TransferRequest
-
- interface TransferRequest {
- // Nonce to make the request idempotent. Requests with the same
- // ``transaction_uid`` that differ in any of the other fields
- // are rejected.
- request_uid: HashCode;
-
- // Amount to transfer.
- amount: Amount;
-
- // Base URL of the exchange. Shall be included by the bank gateway
- // in the appropriate section of the wire transfer details.
- exchange_base_url: string;
-
- // Wire transfer identifier chosen by the exchange,
- // used by the merchant to identify the Taler order(s)
- // associated with this wire transfer.
- wtid: ShortHashCode;
-
- // The recipient's account identifier as a payto URI.
- credit_account: string;
- }
-
-
--------------------------------
Querying the transaction history
--------------------------------
-.. http:get:: ${BASE_URL}/history/incoming
+.. http:get:: /history/incoming
Return a list of transactions made from or to the exchange.
@@ -144,7 +175,7 @@ Querying the transaction history
* A value that is **smaller** than all other row IDs if *delta* is **positive**.
* A value that is **larger** than all other row IDs if *delta* is **negative**.
- **Request**
+ **Request:**
:query start: *Optional.*
Row identifier to explicitly set the *starting point* of the query.
@@ -157,20 +188,33 @@ Querying the transaction history
the bank may return a response immediately or after waiting only a fraction
of ``long_poll_ms``.
- **Response**
+ **Response:**
- :http:statuscode:`200 OK`: JSON object of type `IncomingHistory`.
- :http:statuscode:`400 Bad request`: Request malformed. The bank replies with an `ErrorDetail` object.
- :http:statuscode:`401 Unauthorized`: Authentication failed, likely the credentials are wrong.
- :http:statuscode:`404 Not found`: The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object.
+ :http:statuscode:`200 OK`:
+ JSON object of type `IncomingHistory`.
+ :http:statuscode:`204 No content`:
+ There are not transactions to report (under the given filter).
+ :http:statuscode:`400 Bad request`:
+ Request malformed. The bank replies with an `ErrorDetail` object.
+ :http:statuscode:`401 Unauthorized`:
+ Authentication failed, likely the credentials are wrong.
+ :http:statuscode:`404 Not found`:
+ The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object.
+
+ **Details:**
.. ts:def:: IncomingHistory
interface IncomingHistory {
-
// Array of incoming transactions.
incoming_transactions : IncomingBankTransaction[];
+ // Payto URI to identify the receiver of funds.
+ // This must be one of the exchange's bank accounts.
+ // Credit account is shared by all incoming transactions
+ // as per the nature of the request.
+ credit_account: string;
+
}
.. ts:def:: IncomingBankTransaction
@@ -194,10 +238,6 @@ Querying the transaction history
// Amount transferred.
amount: Amount;
- // Payto URI to identify the receiver of funds.
- // This must be one of the exchange's bank accounts.
- credit_account: string;
-
// Payto URI to identify the sender of funds.
debit_account: string;
@@ -235,7 +275,7 @@ Querying the transaction history
}
-.. http:get:: ${BASE_URL}/history/outgoing
+.. http:get:: /history/outgoing
Return a list of transactions made by the exchange, typically to a merchant.
@@ -263,7 +303,7 @@ Querying the transaction history
* A value that is **smaller** than all other row IDs if *delta* is **positive**.
* A value that is **larger** than all other row IDs if *delta* is **negative**.
- **Request**
+ **Request:**
:query start: *Optional.*
Row identifier to explicitly set the *starting point* of the query.
@@ -276,26 +316,38 @@ Querying the transaction history
the bank may return a response immediately or after waiting only a fraction
of ``long_poll_ms``.
- **Response**
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ JSON object of type `OutgoingHistory`.
+ :http:statuscode:`204 No content`:
+ There are not transactions to report (under the given filter).
+ :http:statuscode:`400 Bad request`:
+ Request malformed. The bank replies with an `ErrorDetail` object.
+ :http:statuscode:`401 Unauthorized`:
+ Authentication failed, likely the credentials are wrong.
+ :http:statuscode:`404 Not found`:
+ The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object.
- :http:statuscode:`200 OK`: JSON object of type `OutgoingHistory`.
- :http:statuscode:`400 Bad request`: Request malformed. The bank replies with an `ErrorDetail` object.
- :http:statuscode:`401 Unauthorized`: Authentication failed, likely the credentials are wrong.
- :http:statuscode:`404 Not found`: The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object.
+ **Details:**
.. ts:def:: OutgoingHistory
interface OutgoingHistory {
-
// Array of outgoing transactions.
outgoing_transactions : OutgoingBankTransaction[];
+ // Payto URI to identify the sender of funds.
+ // This must be one of the exchange's bank accounts.
+ // Credit account is shared by all incoming transactions
+ // as per the nature of the request.
+ debit_account: string;
+
}
.. ts:def:: OutgoingBankTransaction
interface OutgoingBankTransaction {
-
// Opaque identifier of the returned record.
row_id: SafeUint64;
@@ -308,10 +360,6 @@ Querying the transaction history
// Payto URI to identify the receiver of funds.
credit_account: string;
- // Payto URI to identify the sender of funds.
- // This must be one of the exchange's bank accounts.
- debit_account: string;
-
// The wire transfer ID in the outgoing transaction.
wtid: ShortHashCode;
@@ -327,26 +375,14 @@ Wire Transfer Test APIs
Endpoints in this section are only used for integration tests and never
exposed by bank gateways in production.
-.. http:post:: ${BASE_URL}/admin/add-incoming
+.. _twg-admin-add-incoming:
+
+.. http:post:: /admin/add-incoming
Simulate a transfer from a customer to the exchange. This API is *not*
idempotent since it's only used in testing.
- **Request:** The body of this request must have the format of a `AddIncomingRequest`.
-
- **Response:**
-
- :http:statuscode:`200 OK`:
- The request has been correctly handled, so the funds have been transferred to
- the recipient's account. The body is a `AddIncomingResponse`.
- :http:statuscode:`400 Bad request`:
- The request is malformed. The bank replies with an `ErrorDetail` object.
- :http:statuscode:`401 Unauthorized`:
- Authentication failed, likely the credentials are wrong.
- :http:statuscode:`404 Not found`:
- The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object.
- :http:statuscode:`409 Conflict`:
- The 'reserve_pub' argument was used previously in another transfer, and the specification mandates that reserve public keys must not be reused.
+ **Request:**
.. ts:def:: AddIncomingRequest
@@ -365,11 +401,25 @@ exposed by bank gateways in production.
debit_account: string;
}
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The request has been correctly handled, so the funds have been transferred to
+ the recipient's account. The body is a `AddIncomingResponse`.
+ :http:statuscode:`400 Bad request`:
+ The request is malformed. The bank replies with an `ErrorDetail` object.
+ :http:statuscode:`401 Unauthorized`:
+ Authentication failed, likely the credentials are wrong.
+ :http:statuscode:`404 Not found`:
+ The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object.
+ :http:statuscode:`409 Conflict`:
+ The 'reserve_pub' argument was used previously in another transfer, and the specification mandates that reserve public keys must not be reused.
+
+ **Details:**
.. ts:def:: AddIncomingResponse
interface AddIncomingResponse {
-
// Timestamp that indicates when the wire transfer will be executed.
// In cases where the wire transfer gateway is unable to know when
// the wire transfer will be executed, the time at which the request
diff --git a/core/api-challenger.rst b/core/api-challenger.rst
new file mode 100644
index 00000000..759d4e70
--- /dev/null
+++ b/core/api-challenger.rst
@@ -0,0 +1,495 @@
+..
+ This file is part of GNU TALER.
+ Copyright (C) 2023, 2024 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Christian Grothoff
+
+.. _challenger-api:
+
+======================
+Challenger Service API
+======================
+
+The challenger service validates that a user is able to receive challenges at
+an address (such as e-mail or SMS) and allows an OAuth 2.0 client to obtain
+access to these validated addresses.
+
+The high-level flow is that an OAuth 2.0 client is first registered with the
+challenger service (via command-line). Using the command-line tool will print
+the resulting client ID to the console.
+
+.. note::
+
+ The current service mandates that redirection URIs
+ start with "http://" or "https://". See issue #7838
+ for what should be done to lift this restriction.
+
+.. note::
+
+ Right now, registration of a unique redirection URI is *mandatory* for
+ each client. If multiple redirection URIs are needed, it is suggested to
+ just register additional clients. (While OAuth 2.0 would support not
+ registering fixed redirection URIs with a client, this is not recommended
+ as it would create an open redirector.)
+
+Once a client is registered, that client can use the challenger service when
+it needs a user to prove that the user is able to receive messages at a
+particular address. However, asking a user to prove access to a particular
+address can be expensive as it may involve sending an SMS or even postal mail
+depending on the type of address. Thus, challenger does not allow a user
+agent to begin an address validation process without prior approval by a
+registered client. Thus, the process begins with a ``/setup/$CLIENT_ID`` request where a
+client requests challenger to begin an address validation request. The
+``/setup/$CLIENT_ID`` response contains a ``nonce`` which is then used to construct the
+URL of the endpoint to which the client must redirect the user-agent to begin
+the address validation and authorization process.
+
+The client then redirects the user-agent to the ``/authorize/$NONCE`` endpoint
+of the challenger service, adding its ``state``, ``client_id`` and
+``redirect_uri`` as query parameters. The ``redirect_uri`` must match the
+redirect URI registered with the client. From this endpoint, the challenger
+service will return a Web page asking the user to provide its address.
+
+.. note::
+
+ Challenger is a bit unusual in that the ``$NONCE`` in the endpoint URL
+ makes the authorization endpoint URL (deliberately) unpredictable, while
+ for many other OAuth 2.0 APIs this endpoint is static. However, this is
+ compliant with OAuth 2.0 as determining the authorization URL is left out
+ of the scope of the standard.
+
+When the user has filled in the form with their address, it will be submitted
+to the ``/challenge/$NONCE`` endpoint and the challenger service will send a
+challenge to the user's address and generate an HTML form asking the user to
+enter the received challenge value.
+
+The user can then enter the answer to the challenge which is then submitted to
+the ``/solve/$NONCE`` endpoint. If the answer is correct, the user agent will
+be redirected to the client redirect URI that was specified by the OAuth 2.0
+client upon ``/authorize``, together with an authorization grant encoded in
+the redirection URI.
+
+Given this authorization grant, the OAuth 2.0 client can then use the
+``/token`` endpoint to obtain an access token which will grant it access to
+the resource.
+
+Using the ``/info`` endpoint the client can then finally obtain the (now)
+verified address of the user.
+
+.. contents:: Table of Contents
+ :local:
+
+.. include:: tos.rst
+
+-----------------------
+Receiving Configuration
+-----------------------
+
+.. http:get:: /config
+
+ Obtain the key configuration settings of the storage service.
+ This specification corresponds to ``current`` protocol being version **1**.
+
+ **Response:**
+
+ Returns a `ChallengerTermsOfServiceResponse`.
+
+ .. ts:def:: ChallengerTermsOfServiceResponse
+
+ interface ChallengerTermsOfServiceResponse {
+ // Name of the service
+ name: "challenger";
+
+ // libtool-style representation of the Challenger protocol version, see
+ // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
+ // The format is "current:revision:age".
+ version: string;
+
+ // URN of the implementation (needed to interpret 'revision' in version).
+ // @since v0, may become mandatory in the future.
+ implementation?: string;
+
+ }
+
+.. _challenger-setup:
+
+-----
+Setup
+-----
+
+.. http:post:: /setup/$CLIENT_ID
+
+ This endpoint is used by the client to authorize the execution of an address
+ validation on its behalf. An ``Authorization`` header (for now always using
+ a ``Bearer`` token) should be included to provide the client's credentials
+ to authorize access to the challenger service. This token must match the
+ ``client_secret`` from the registration of the client with the challenger
+ service (which will also be used in the later ``/token`` request).
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ Response is a `ChallengeSetupResponse`.
+ :http:statuscode:`404 Not found`:
+ The backup service is unaware of a matching client.
+ or the credentials of the client are invalid.
+
+ **Details::**
+
+ .. ts:def:: ChallengeSetupResponse
+
+ interface ChallengeSetupResponse {
+ // Nonce to use when constructing ``/authorize`` endpoint.
+ nonce: string;
+ }
+
+
+.. _challenger-login:
+
+-----
+Login
+-----
+
+.. http:get:: /authorize/$NONCE
+.. http:post:: /authorize/$NONCE
+
+ This is the "authorization" endpoint of the OAuth 2.0 protocol. This
+ endpoint is used by the user-agent. It will return a form to enter the
+ address.
+
+ The NONCE is a unique value identifying the challenge, should be shown to
+ the user so that they can recognize it when they receive the TAN code.
+
+ This endpoint typically also supports requests with the "Accept" header
+ requesting "text/html". In this case, an HTML response using the template
+ :ref:`enter-$ADDRESS_TYPE-form <challenger_enter-address_type-form>` is
+ returned. If the backend installation does not include the required HTML
+ templates, a 406 status code is returned.
+
+
+ **Request:**
+
+ :query response_type: Must be ``code``
+ :query client_id: Identifier of the client.
+ :query redirect_uri: URI-encoded redirection URI to use upon authorization.
+ :query state: Arbitrary client state to associate with the request.
+ :query scope: Not supported, any value is accepted.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ If the request ask for application/json then the response is
+ a `ChallengeStatus`. Since protocol **v1**.
+ Otherwise, the body contains a form to be submitted by the user-agent
+ using the template :ref:`enter-$ADDRESS_TYPE-form <challenger_enter-address_type-form>`.
+ The form will ask the user to specify their address.
+ :http:statuscode:`400 Bad Request`:
+ The request does not follow the spec.
+ If the request ask for application/json the response will include error
+ code, hint and detail. Since protocol **v1**.
+ Otherwise, the body contains information using the template :ref:`invalid-request <challenger_invalid-request>`.
+ :http:statuscode:`404 Not found`:
+ The service is unaware of a matching challenge.
+ If the request ask for application/json the response will include error
+ code, hint and detail. Since protocol **v1**.
+ Otherwise, the body contains information using the template :ref:`validation-unknown <challenger_validation-unknown>`.
+ :http:statuscode:`406 Not Acceptable`:
+ The client ask for "text/html" and the backend installation does
+ not include the required HTML templates.
+ :http:statuscode:`500 Internal Server Error`:
+ Server is not able to respond due to internal problems.
+ If the request ask for application/json the response will include error
+ code, hint and detail. Since protocol **v1**.
+ Otherwise, the body contains information using the template :ref:`internal-error <challenger_internal-error>`.
+
+ .. ts:def:: ChallengeStatus
+
+ interface ChallengeStatus {
+ // Object; map of keys (names of the fields of the address
+ // to be entered by the user) to objects with a "regex" (string)
+ // containing an extended Posix regular expression for allowed
+ // address field values, and a "hint"/"hint_i18n" giving a
+ // human-readable explanation to display if the value entered
+ // by the user does not match the regex. Keys that are not mapped
+ // to such an object have no restriction on the value provided by
+ // the user. See "ADDRESS_RESTRICTIONS" in the challenger configuration.
+ restrictions: Object;
+
+ // indicates if the given address cannot be changed anymore, the
+ // form should be read-only if set to true.
+ fix_address: boolean;
+
+ // form values from the previous submission if available, details depend
+ // on the ``ADDRESS_TYPE``, should be used to pre-populate the form
+ last_address: Object;
+
+ // number of times the address can still be changed, may or may not be
+ // shown to the user
+ changes_left: Integer;
+ }
+
+
+.. _challenger-challenge:
+
+---------
+Challenge
+---------
+
+.. http:post:: /challenge/$NONCE
+
+ This endpoint is used by the user-agent to submit the address to which a
+ challenge should be sent by the challenger service.
+
+ **Request:**
+
+ Body should use the mime-type "application/x-www-form-urlencoded".
+ The posted form data must contain an "address".
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ If the request ask for application/json the response is `ChallengeCreateResponse`. Since protocol **v1**.
+ Otherwise, the body contains a form asking for the answer to
+ the challenge to be entered by the user using the
+ template :ref:`enter-tan-form <challenger_enter-tan-form>`.
+ :http:statuscode:`400 Bad Request`:
+ The request does not follow the spec.
+ If the request ask for application/json the response will include error
+ code, hint and detail. Since protocol **v1**.
+ Otherwise, the body contains information using the template :ref:`invalid-request <challenger_invalid-request>`.
+ :http:statuscode:`404 Not Found`:
+ The service is unaware of a matching challenge.
+ If the request ask for application/json the response will include error
+ code, hint and detail. Since protocol **v1**.
+ Otherwise, the body contains information using the template :ref:`validation-unknown <challenger_validation-unknown>`.
+ :http:statuscode:`406 Not Acceptable`:
+ The client ask for "text/html" and the backend installation does
+ not include the required HTML templates.
+ :http:statuscode:`429 Too Many Requests`:
+ There have been too many attempts to request challenge
+ transmissions for this $NONCE. The user-agent should
+ wait and (eventually) request a fresh nonce to be set
+ up by the client.
+ :http:statuscode:`500 Internal Server Error`:
+ Server is not able to respond due to internal problems.
+ If the request ask for application/json the response will include error
+ code, hint and detail. Since protocol **v1**.
+ Otherwise, the body contains information using the template :ref:`internal-error <challenger_internal-error>`.
+
+ .. ts:def:: ChallengeCreateResponse
+
+ interface ChallengeCreateResponse {
+
+ // how many more attempts are allowed, might be shown to the user,
+ // highlighting might be appropriate for low values such as 1 or 2 (the
+ // form will never be used if the value is zero)
+ attempts_left: Integer;
+
+ // the address that is being validated, might be shown or not
+ address: Object;
+
+ // true if we just retransmitted the challenge, false if we sent a
+ // challenge recently and thus refused to transmit it again this time;
+ // might make a useful hint to the user
+ transmitted: boolean;
+
+ // timestamp explaining when we would re-transmit the challenge the next
+ // time (at the earliest) if requested by the user
+ next_tx_time: string;
+
+ }
+
+
+
+.. _challenger-solve:
+
+-----
+Solve
+-----
+
+.. http:post:: /solve/$NONCE
+
+ Used by the user-agent to submit an answer to the challenge. If the answer
+ is correct, the user will be redirected to the client's redirect URI,
+ otherwise the user may be given another chance to complete the process.
+
+ **Request:**
+
+ Depends on the form from ``/challenge``. TBD.
+
+ **Response:**
+
+ :http:statuscode:`302 Found`:
+ The user is redirected to the redirect URI of the client to pass the
+ grant to the client. The target will be the redirect URI specified
+ by the client (during registration and again upon ``/authorize``),
+ plus a ``code`` argument with the authorization code, and the
+ ``state`` argument from the ``/authorize`` endpoint.
+ :http:statuscode:`400 Bad Request`:
+ The request does not follow the spec.
+ If the request ask for application/json the response will include error
+ code, hint and detail. Since protocol **v1**.
+ Otherwise, the body contains information using the template :ref:`invalid-request <challenger_invalid-request>`.
+ :http:statuscode:`403 Forbidden`:
+ If the request ask for application/json the response is `InvalidPinResponse`. Since protocol **v1**.
+ Otherwise, the body contains information using the template :ref:`invalid-pin <challenger_invalid-pin>`.
+ :http:statuscode:`404 Not found`:
+ The service is unaware of a matching challenge.
+ If the request ask for application/json the response will include error
+ code, hint and detail. Since protocol **v1**.
+ Otherwise, the body contains information using the template :ref:`validation-unknown <challenger_validation-unknown>`.
+ :http:statuscode:`429 Too Many Requests`:
+ There have been too many attempts to solve the challenge
+ for this address (and $NONCE). The user-agent should
+ either try a different address (or wait and (eventually)
+ request a fresh nonce to be set up by the client).
+ :http:statuscode:`500 Internal Server Error`:
+ Server is not able to respond due to internal problems.
+ If the request ask for application/json the response will include error
+ code, hint and detail. Since protocol **v1**.
+ Otherwise, the body contains information using the template :ref:`internal-error <challenger_internal-error>`.
+
+ .. ts:def:: InvalidPinResponse
+
+ interface InvalidPinResponse {
+ // numeric Taler error code, should be shown to indicate the error
+ // compactly for reporting to developers
+ ec: Integer;
+
+ // human-readable Taler error code, should be shown for the user to
+ // understand the error
+ hint: string;
+
+ // how many times is the user still allowed to change the address;
+ // if 0, the user should not be shown a link to jump to the
+ // address entry form
+ addresses_left: Integer;
+
+ // how many times might the PIN still be retransmitted
+ pin_transmissions_left: Integer;
+
+ // how many times might the user still try entering the PIN code
+ auth_attempts_left: Integer;
+
+ // if true, the PIN was not even evaluated as the user previously
+ // exhausted the number of attempts
+ exhausted: boolean;
+
+ // if true, the PIN was not even evaluated as no challenge was ever
+ // issued (the user must have skipped the step of providing their
+ // address first!)
+ no_challenge: boolean;
+ }
+
+.. _challenger-auth:
+
+----
+Auth
+----
+
+.. http:post:: /token
+
+ This is the token endpoint of the OAuth 2.0 specification.
+ This endpoint is used by the client to provide its authorization code,
+ demonstrating that it has the right to learn a particular user's validated
+ address. In return, the challenger service returns the access token.
+ Renewal is not supported.
+
+ **Request:**
+
+ The request must include an ``application/www-form-urlencoded`` body
+ specifying the ``client_id``, ``redirect_uri``, ``client_secret``, ``code``
+ and ``grant_type``. The ``grant_type`` must be set to
+ ``authorization_code``. The ``redirect_uri`` must match the URI from
+ ``/authorize``. The ``code`` must be the authorization code that ``/solve``
+ returned to the user. The ``client_id`` and ``client_secret`` must match
+ the usual client credentials.
+
+ **Response:**
+
+ Error responses follow RFC 6749, section 5.2 with an "error" field in JSON,
+ as well as also returning GNU Taler style error messages.
+
+ :http:statuscode:`200 OK`:
+ The body will be a `ChallengerAuthResponse`
+ :http:statuscode:`403 Forbidden`:
+ The credentials of the client are invalid.
+ :http:statuscode:`404 Not found`:
+ The service is unaware of a matching login process.
+
+ **Details::**
+
+ .. ts:def:: ChallengerAuthResponse
+
+ interface ChallengerAuthResponse {
+ // Token used to authenticate access in ``/info``.
+ access_token: string;
+
+ // Type of the access token.
+ token_type: "Bearer";
+
+ // Amount of time that an access token is valid (in seconds).
+ expires_in: Integer;
+
+ }
+
+
+.. _challenger-info:
+
+----
+Info
+----
+
+.. http:get:: /info
+
+ This userinfo endpoint of the OAuth 2.0 specification.
+ This endpoint is used by the client to obtain the user's validated address.
+
+ **Request:**
+
+ Must include the token returned to the client from the ``/token`` endpoint
+ as a ``Bearer`` token in an ``Authorization`` header.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The body contains the address as a `ChallengerInfoResponse`.
+ :http:statuscode:`403 Forbidden`:
+ The bearer token is missing or invalid (malformed).
+ :http:statuscode:`404 Not found`:
+ The bearer token is invalid (includes unknown or expired).
+
+ **Details::**
+
+ .. ts:def:: ChallengerInfoResponse
+
+ interface ChallengerInfoResponse {
+
+ // Unique ID of the record within Challenger
+ // (identifies the rowid of the token).
+ id: Integer;
+
+ // Address that was validated.
+ // Key-value pairs, details depend on the
+ // address_type.
+ address: Object;
+
+ // Type of the address.
+ address_type: string;
+
+ // How long do we consider the address to be
+ // valid for this user.
+ expires: Timestamp;
+
+ }
diff --git a/core/api-common.rst b/core/api-common.rst
index 7ee4769f..521b2fc0 100644
--- a/core/api-common.rst
+++ b/core/api-common.rst
@@ -18,10 +18,14 @@
.. _http-common:
-=================================
-Common Taler HTTP API Conventions
-=================================
+.. _foo_bar:
+==================================
+Conventions for Taler RESTful APIs
+==================================
+
+.. contents:: Table of Contents
+ :local:
-------------------------
HTTP Request and Response
@@ -69,6 +73,8 @@ handle the error as if an internal error (500) had been returned.
requests.
:http:statuscode:`400 Bad request`:
One of the arguments to the request is missing or malformed.
+ :http:statuscode:`415 Unsupported Media Type`:
+ The Content-Type header was not set, or it was set to an unsupported MIME type.
:http:statuscode:`500 Internal server error`:
This always indicates some serious internal operational error of the exchange,
such as a program bug, database problems, etc., and must not be used for
@@ -117,7 +123,7 @@ handle the error as if an internal error (500) had been returned.
// Name of the object that was bogus (if applicable).
object?: string;
- // Name of the currency than was problematic (if applicable).
+ // Name of the currency that was problematic (if applicable).
currency?: string;
// Expected type (if applicable).
@@ -125,6 +131,9 @@ handle the error as if an internal error (500) had been returned.
// Type that was provided instead (if applicable).
type_actual?: string;
+
+ // Extra information that doesn't fit into the above (if applicable).
+ extra?: Object;
}
-----------------------
@@ -183,6 +192,29 @@ Examples:
to decide whether it will talk to the service.
+.. _error-codes:
+
+-----------
+Error Codes
+-----------
+
+All error codes used in GNU Taler are defined in
+`GANA <https://git.gnunet.org/gana.git/tree/gnu-taler-error-codes/>`__.
+
+This centralized registry also contains generators that create enumerations
+and mappings from error codes to HTTP status codes and human-readable error
+messages for various programming languages.
+
+All error codes have numeric values below 100 or above 1000, so as to never be
+confused with HTTP status codes. A value of 0 is reserved for "no error" or
+"success".
+
+In C, the respective enumeration is the ``enum TALER_ErrorCode``.
+
+Developers may have to re-run ``bootstrap`` and/or update their Git
+submodules to ensure that they have the lastest GANA registry.
+
+
.. _encodings-ref:
----------------
@@ -209,6 +241,7 @@ resulting encoding.
Hash codes
^^^^^^^^^^
+
Hash codes are strings representing base32 encoding of the respective
hashed data. See `base32`_.
@@ -222,6 +255,40 @@ hashed data. See `base32`_.
// 32-byte hash code.
type ShortHashCode = string;
+.. ts:def:: WireSalt
+
+ // 16-byte salt.
+ type WireSalt = string;
+
+.. ts:def:: SHA256HashCode
+
+ type SHA256HashCode = ShortHashCode;
+
+.. ts:def:: SHA512HashCode
+
+ type SHA512HashCode = HashCode;
+
+.. ts:def:: CSNonce
+
+ // 32-byte nonce value, must only be used once.
+ type CSNonce = string;
+
+.. ts:def:: RefreshMasterSeed
+
+ // 32-byte nonce value, must only be used once.
+ type RefreshMasterSeed = string;
+
+.. ts:def:: Cs25519Point
+
+ // 32-byte value representing a point on Curve25519.
+ type Cs25519Point = string;
+
+.. ts:def:: Cs25519Scalar
+
+ // 32-byte value representing a scalar multiplier
+ // for scalar operations on points on Curve25519.
+ type Cs25519Scalar = string;
+
Safe Integers
^^^^^^^^^^^^^
@@ -241,6 +308,17 @@ Large numbers
Large numbers such as RSA blinding factors and 256 bit keys, are transmitted
as other binary data in Crockford Base32 encoding.
+Decimal numbers
+^^^^^^^^^^^^^^^
+
+..
+ FIXME: explain the representation with strings.
+
+.. ts:def:: DecimalNumber
+
+ // Number with at most 8 fractional digits.
+ type DecimalNumber = string;
+
Timestamps
^^^^^^^^^^
@@ -249,18 +327,19 @@ Timestamps are represented by the following structure:
.. ts:def:: Timestamp
interface Timestamp {
- // Milliseconds since epoch, or the special
+ // Seconds since epoch, or the special
// value "never" to represent an event that will
// never happen.
- t_ms: number | "never";
+ t_s: number | "never";
}
.. ts:def:: RelativeTime
- interface Duration {
- // Duration in milliseconds or "forever"
- // to represent an infinite duration.
- d_ms: number | "forever";
+ interface RelativeTime {
+ // Duration in microseconds or "forever"
+ // to represent an infinite duration. Numeric
+ // values are capped at 2^53 - 1 inclusive.
+ d_us: number | "forever";
}
@@ -275,6 +354,45 @@ Integers
// JavaScript numbers restricted to integers.
type Integer = number;
+Floats
+^^^^^^
+
+.. ts:def:: Float
+
+ // JavaScript numbers.
+ type Float = number;
+
+Ages
+^^^^
+
+.. ts:def:: Age
+
+ // An age is an integer between 0 and 255 measured in years.
+ type Age = number;
+
+Versions
+^^^^^^^^
+
+We use the type ``LibtoolVersion`` in the design documents to refer to a string
+that represents a version with the semantic as defined by
+`libtool <https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html>`__.
+
+.. ts:def:: LibtoolVersion
+
+ // Version information in libtool version format and semantics
+ // current[:revision[:age]], f.e. "1", "2:0" or "3:1:2".
+ // see https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html.
+ type LibtoolVersion = string;
+
+We use the type ``SemVer`` to refer to a string that represents a version with
+the semantic as defined by `semantic versioning <https://semver.org/>`__.
+
+.. ts:def:: SemVer
+
+ // Version information in semantic versioning format and semantics,
+ // like "X.Z.Y", see https://semver.org/.
+ type SemVer = string;
+
Objects
^^^^^^^
@@ -283,6 +401,76 @@ Objects
// JavaScript objects, no further restrictions.
type Object = object;
+
+Contact details
+^^^^^^^^^^^^^^^
+
+.. ts:def:: EmailAddress
+
+ type EmailAddress = string;
+
+.. ts:def:: PhoneNumber
+
+ type PhoneNumber = string;
+
+Phone numbers should start with the ``+`` symbol and the country code.
+
+Permissions
+^^^^^^^^^^^
+
+This type epresses which permissions for a subject
+apply on a resource.
+
+.. ts:def:: LibeufinPermission
+
+ interface LibeufinPermission {
+ subjectType: string;
+ subjectId: string;
+ resourceType: string;
+ resourceId: string;
+ permissionName: string
+ }
+
+
+Fetch params
+^^^^^^^^^^^^
+
+.. _fetch-params:
+
+.. ts:def:: FetchParams
+
+ interface FetchParams {
+
+ // Because transactions are delivered by banks in "batches",
+ // then every batch can have different qualities. This value
+ // lets the request specify which type of batch ought to be
+ // returned. Currently, the following two type are supported:
+ //
+ // 'report': typically includes only non booked transactions.
+ // 'statement': typically includes only booked transactions.
+ level: "report" | "statement" | "all";
+
+ // This type indicates the time range of the query.
+ // It allows the following values:
+ //
+ // 'latest': retrieves the last transactions from the bank.
+ // If there are older unread transactions, those will *not*
+ // be downloaded.
+ //
+ // 'all': retrieves all the transactions from the bank,
+ // until the oldest.
+ //
+ // 'previous-days': currently *not* implemented, it will allow
+ // the request to download transactions from
+ // today until N days before.
+ //
+ // 'since-last': retrieves all the transactions since the last
+ // time one was downloaded.
+ //
+ rangeType: "latest" | "all" | "previous-days" | "since-last";
+ };
+
+
Keys
^^^^
@@ -305,6 +493,20 @@ Keys
// converted to Crockford `Base32`.
type EddsaPrivateKey = string;
+.. ts:def:: Edx25519PublicKey
+
+ // Edx25519 public keys are points on Curve25519 and represented using the
+ // standard 256 bits Ed25519 compact format converted to Crockford
+ // `Base32`.
+ type Edx25519PublicKey = string;
+
+.. ts:def:: Edx25519PrivateKey
+
+ // Edx25519 private keys are always points on Curve25519
+ // and represented using the standard 256 bits Ed25519 compact format,
+ // converted to Crockford `Base32`.
+ type Edx25519PrivateKey = string;
+
.. ts:def:: EcdhePublicKey
// EdDSA and ECDHE public keys always point on Curve25519
@@ -312,6 +514,12 @@ Keys
// converted to Crockford `Base32`.
type EcdhePublicKey = string;
+.. ts:def:: CsRPublic
+
+ // Point on Curve25519 represented using the standard 256 bits Ed25519 compact format,
+ // converted to Crockford `Base32`.
+ type CsRPublic = string;
+
.. ts:def:: EcdhePrivateKey
// EdDSA and ECDHE public keys always point on Curve25519
@@ -335,8 +543,31 @@ Blinded coin
.. ts:def:: CoinEnvelope
- // Blinded coin's `public EdDSA key <eddsa-coin-pub>`, `base32` encoded.
- type CoinEnvelope = string;
+ // The type of a coin's blinded envelope depends on the cipher that is used
+ // for signing with a denomination key.
+ type CoinEnvelope = RSACoinEnvelope | CSCoinEnvelope ;
+
+.. ts:def:: RSACoinEnvelope
+
+ // For denomination signatures based on RSA, the planchet is just a blinded
+ // coin's `public EdDSA key <eddsa-coin-pub>`.
+ interface RSACoinEnvelope {
+ cipher: "RSA" | "RSA+age_restricted";
+ rsa_blinded_planchet: BlindedRsaSignature;
+ }
+
+.. ts:def:: CSCoinEnvelope
+
+ // For denomination signatures based on Blind Clause-Schnorr, the planchet
+ // consists of the public nonce and two Curve25519 scalars which are two
+ // blinded challenges in the Blinded Clause-Schnorr signature scheme.
+ // See https://taler.net/papers/cs-thesis.pdf for details.
+ interface CSCoinEnvelope {
+ cipher: "CS" | "CS+age_restricted";
+ cs_nonce: string; // Crockford `Base32` encoded
+ cs_blinded_c0: string; // Crockford `Base32` encoded
+ cs_blinded_c1: string; // Crockford `Base32` encoded
+ }
.. ts:def:: DenominationBlindingKeyP
@@ -346,6 +577,25 @@ Blinded coin
type DenominationBlindingKeyP = string;
+. _unblinded-coin:
+
+Unblinded coin
+^^^^^^^^^^^^^^
+
+.. ts:def:: UnblindedSignature
+
+ // The type of a coin's unblinded signature depends on the cipher that was used
+ // for signing with a denomination key.
+ // Note that for now, only RSA is supported.
+ type UnblindedSignature = RsaUnblindedSignature;
+
+.. ts:def:: RsaUnblindedSignature
+
+ interface RsaUnblindedSignature {
+ cipher: "RSA";
+ rsa_signature: RsaSignature;
+ }
+
.. _signature:
@@ -359,6 +609,12 @@ Signatures
// binary-encoded objects with just the R and S values (base32_ binary-only).
type EddsaSignature = string;
+.. ts:def:: Edx25519Signature
+
+ // Edx25519 signatures are transmitted as 64-bytes `base32`
+ // binary-encoded objects with just the R and S values (base32_ binary-only).
+ type Edx25519Signature = string;
+
.. ts:def:: RsaSignature
// `base32` encoded RSA signature.
@@ -374,6 +630,13 @@ Signatures
// `base32` encoded RSA blinding secret.
type RsaBlindingKeySecret = string;
+.. ts:def:: DenominationBlindingKeySecret
+
+ // Union, not (!) discriminated!
+ // (Note: CS Blinding Key secret is yet to be defined&added here).
+ type DenominationBlindingKeySecret =
+ | RsaBlindingKeySecret;
+
.. _amount:
Amounts
@@ -402,6 +665,12 @@ The following constrains apply for a valid amount:
An amount that is prefixed with a ``+`` or ``-`` character is also used in certain contexts.
When no sign is present, the amount is assumed to be positive.
+.. note::
+
+ In some setups, when Libeufin-Bank offers cashouts towards traditional
+ currencies like EUR for example, the fractional part gets restricted
+ to at most 2 digits.
+
.. ts:def:: SignedAmount
type SignedAmount = string;
@@ -496,12 +765,65 @@ All elliptic curve operations are on Curve25519. Public and private keys are
thus 32 bytes, and signatures 64 bytes. For hashing, including HKDFs, Taler
uses 512-bit hash codes (64 bytes).
+.. _HashCode:
.. sourcecode:: c
struct GNUNET_HashCode {
uint8_t hash[64]; // usually SHA-512
};
+.. sourcecode:: c
+
+ struct TALER_DenominationHash {
+ struct GNUNET_HashCode hash;
+ };
+
+.. sourcecode:: c
+
+ struct TALER_PrivateContractHash {
+ struct GNUNET_HashCode hash;
+ };
+
+.. sourcecode:: c
+
+ struct TALER_ExtensionsPolicyHash {
+ struct GNUNET_HashCode hash;
+ };
+
+.. sourcecode:: c
+
+ struct TALER_MerchantWireHash {
+ struct GNUNET_HashCode hash;
+ };
+
+.. _PaytoHash:
+.. sourcecode:: c
+
+ struct TALER_PaytoHash {
+ struct GNUNET_ShortHashCode hash;
+ };
+
+.. _BlindedCoinHash:
+.. sourcecode:: c
+
+ struct TALER_BlindedCoinHash {
+ struct GNUNET_HashCode hash;
+ };
+
+.. sourcecode:: c
+
+ struct TALER_CoinPubHash {
+ struct GNUNET_HashCode hash;
+ };
+
+.. sourcecode:: c
+
+ struct TALER_OutputCommitmentHash {
+ struct GNUNET_HashCode hash;
+ };
+
+
+
.. _TALER_EcdhEphemeralPublicKeyP:
.. sourcecode:: c
@@ -546,6 +868,28 @@ uses 512-bit hash codes (64 bytes).
uint8_t ecdhe_priv[32];
};
+
+.. _AmlDecisionState:
+.. sourcecode:: c
+
+ enum TALER_AmlDecisionState {
+ NORMAL, PENDING, FROZEN
+ };
+
+.. _AmlOfficerPublicKeyP:
+.. sourcecode:: c
+
+ struct TALER_AmlOfficerPublicKeyP {
+ uint8_t eddsa_pub[32];
+ };
+
+.. _AmlOfficerPrivateKeyP:
+.. sourcecode:: c
+
+ struct TALER_AmlOfficerPrivateKeyP {
+ uint8_t eddsa_priv[32];
+ };
+
.. _sign-key-pub:
.. sourcecode:: c
@@ -630,10 +974,19 @@ uses 512-bit hash codes (64 bytes).
uint8_t enc[sizeof (struct TALER_LinkSecretP)];
};
+.. _eddsa-token-pub:
+.. sourcecode:: c
+
+ union TALER_TokenPublicKeyP {
+ uint8_t eddsa_pub[32];
+ uint8_t ecdhe_pub[32];
+ };
+
.. _Signatures:
Signatures
^^^^^^^^^^
+
Any piece of signed data, complies to the abstract data structure given below.
.. sourcecode:: c
@@ -648,9 +1001,11 @@ Any piece of signed data, complies to the abstract data structure given below.
/*From gnunet_crypto_lib.h*/
struct GNUNET_CRYPTO_EccSignaturePurpose {
/**
-
- The following constraints apply for a valid amount:
-
+ * This field equals the number of bytes being signed,
+ * namely 'sizeof (struct Data)'.
+ */
+ uint32_t size;
+ /**
* This field is used to express the context in
* which the signature is made, ensuring that a
* signature cannot be lifted from one part of the protocol
@@ -658,11 +1013,6 @@ Any piece of signed data, complies to the abstract data structure given below.
* exchange's codebase (git://taler.net/exchange).
*/
uint32_t purpose;
- /**
- * This field equals the number of bytes being signed,
- * namely 'sizeof (struct Data)'.
- */
- uint32_t size;
};
@@ -682,11 +1032,44 @@ within the
struct TALER_ReservePublicKeyP reserve_pub;
struct TALER_AmountNBO amount_with_fee;
struct TALER_AmountNBO withdraw_fee;
- struct GNUNET_HashCode h_denomination_pub;
- struct GNUNET_HashCode h_coin_envelope;
+ struct TALER_DenominationHash h_denomination_pub;
+ struct TALER_BlindedCoinHash h_coin_envelope;
+ };
+
+.. _TALER_AgeWithdrawRequestPS:
+.. sourcecode:: c
+
+ struct TALER_AgeWithdrawRequestPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_WALLET_RESERVE_AGE_WITHDRAW
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct TALER_ReservePublicKeyP reserve_pub;
+ /**
+ * This is the running SHA512-hash over n*kappa
+ * `struct TALER_BlindedCoinHash` values
+ */
+ struct GNUNET_HashCode h_commitment;
+ struct TALER_AgeMask mask;
+ uint8_t max_age_group;
};
-.. _TALER_DepositRequestPS:
+.. _TALER_AgeWithdrawConfirmationPS:
+
+.. sourcecode:: c
+
+ struct TALER_AgeWithdrawConfirmationPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_AGE_WITHDRAW
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_HashCode h_commitment;
+ uint32_t noreveal_index;
+ };
+
+
+.. _taler_depositrequestps:
+
.. sourcecode:: c
struct TALER_DepositRequestPS {
@@ -694,27 +1077,35 @@ within the
* purpose.purpose = TALER_SIGNATURE_WALLET_COIN_DEPOSIT
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_HashCode h_contract_terms;
- struct GNUNET_HashCode h_wire;
- struct GNUNET_HashCode h_denom_pub;
+ struct TALER_PrivateContractHash h_contract_terms;
+ struct TALER_AgeCommitmentHash h_age_commitment;
+ struct TALER_ExtensionsPolicyHash h_policy;
+ struct TALER_MerchantWireHash h_wire;
+ struct TALER_DenominationHash h_denom_pub;
struct GNUNET_TIME_AbsoluteNBO timestamp;
struct GNUNET_TIME_AbsoluteNBO refund_deadline;
struct TALER_AmountNBO amount_with_fee;
struct TALER_AmountNBO deposit_fee;
struct TALER_MerchantPublicKeyP merchant;
- union TALER_CoinSpendPublicKeyP coin_pub;
+ struct GNUNET_HashCode wallet_data_hash;
+ /* @since protocol **vSUBSCRIBE** */
+ struct TALER_OutputCommitmentHash h_outputs;
+ /* @since protocol **vSUBSCRIBE** */
+ uint16_t choice_index;
};
.. _TALER_DepositConfirmationPS:
+
.. sourcecode:: c
struct TALER_DepositConfirmationPS {
/**
- * purpose.purpose = TALER_SIGNATURE_WALLET_CONFIRM_DEPOSIT
+ * purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_HashCode h_contract_terms;
- struct GNUNET_HashCode h_wire;
+ struct TALER_PrivateContractHash h_contract_terms;
+ struct TALER_MerchantWireHash h_wire;
+ struct TALER_ExtensionsPolicyHash h_policy;
struct GNUNET_TIME_AbsoluteNBO timestamp;
struct GNUNET_TIME_AbsoluteNBO refund_deadline;
struct TALER_AmountNBO amount_without_fee;
@@ -730,11 +1121,11 @@ within the
* purpose.purpose = TALER_SIGNATURE_WALLET_COIN_MELT
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_HashCode session_hash;
- struct GNUNET_HashCode h_denom_pub;
+ struct TALER_RefreshCommitmentP session_hash;
+ struct TALER_DenominationHash h_denom_pub;
+ struct TALER_AgeCommitmentHash h_age_commitment;
struct TALER_AmountNBO amount_with_fee;
struct TALER_AmountNBO melt_fee;
- union TALER_CoinSpendPublicKeyP coin_pub;
};
.. _TALER_RefreshMeltConfirmationPS:
@@ -745,7 +1136,7 @@ within the
* purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_HashCode session_hash;
+ struct TALER_RefreshCommitmentP session_hash;
uint16_t noreveal_index;
};
@@ -757,7 +1148,6 @@ within the
* purpose.purpose = TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct TALER_MasterPublicKeyP master_public_key;
struct GNUNET_TIME_AbsoluteNBO start;
struct GNUNET_TIME_AbsoluteNBO expire;
struct GNUNET_TIME_AbsoluteNBO end;
@@ -793,7 +1183,7 @@ within the
struct TALER_AmountNBO fee_withdraw;
struct TALER_AmountNBO fee_deposit;
struct TALER_AmountNBO fee_refresh;
- struct GNUNET_HashCode denom_hash;
+ struct TALER_DenominationHash denom_hash;
};
.. _TALER_MasterWireDetailsPS:
@@ -804,7 +1194,10 @@ within the
* purpose.purpose = TALER_SIGNATURE_MASTER_WIRE_DETAILS
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_HashCode h_wire_details;
+ struct TALER_PaytoHash h_wire_details;
+ struct GNUNET_HashCode h_conversion_url;
+ struct GNUNET_HashCode h_credit_restrictions;
+ struct GNUNET_HashCode h_debit_restrictions;
};
.. _TALER_MasterWireFeePS:
@@ -822,6 +1215,41 @@ within the
struct TALER_AmountNBO closing_fee;
};
+.. _TALER_GlobalFeesPS:
+.. sourcecode:: c
+
+ struct TALER_GlobalFeesPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_MASTER_GLOBAL_FEES
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_TIME_AbsoluteNBO start_date;
+ struct GNUNET_TIME_AbsoluteNBO end_date;
+ struct GNUNET_TIME_RelativeNBO purse_timeout;
+ struct GNUNET_TIME_RelativeNBO kyc_timeout;
+ struct GNUNET_TIME_RelativeNBO history_expiration;
+ struct TALER_AmountNBO history_fee;
+ struct TALER_AmountNBO kyc_fee;
+ struct TALER_AmountNBO account_fee;
+ struct TALER_AmountNBO purse_fee;
+ uint32_t purse_account_limit;
+ };
+
+.. _TALER_MasterDrainProfitPS:
+.. sourcecode:: c
+
+ struct TALER_MasterDrainProfitPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_MASTER_DRAIN_PROFITS
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct TALER_WireTransferIdentifierRawP wtid;
+ struct GNUNET_TIME_AbsoluteNBO date;
+ struct TALER_AmountNBO amount;
+ struct GNUNET_HashCode h_section;
+ struct TALER_PaytoHashP h_payto;
+ };
+
.. _TALER_DepositTrackPS:
.. sourcecode:: c
@@ -830,19 +1258,18 @@ within the
* purpose.purpose = TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_HashCode h_contract_terms;
- struct GNUNET_HashCode h_wire;
- struct TALER_MerchantPublicKeyP merchant;
- struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct TALER_PrivateContractHash h_contract_terms;
+ struct TALER_MerchantWireHash h_wire;
+ union TALER_CoinSpendPublicKeyP coin_pub;
};
.. _TALER_WireDepositDetailP:
.. sourcecode:: c
struct TALER_WireDepositDetailP {
- struct GNUNET_HashCode h_contract_terms;
+ struct TALER_PrivateContractHash h_contract_terms;
struct GNUNET_TIME_AbsoluteNBO execution_time;
- struct TALER_CoinSpendPublicKeyP coin_pub;
+ union TALER_CoinSpendPublicKeyP coin_pub;
struct TALER_AmountNBO deposit_value;
struct TALER_AmountNBO deposit_fee;
};
@@ -859,7 +1286,7 @@ within the
struct TALER_AmountNBO total;
struct TALER_AmountNBO wire_fee;
struct TALER_MerchantPublicKeyP merchant_pub;
- struct GNUNET_HashCode h_wire;
+ struct TALER_MerchantWireHash h_wire;
struct GNUNET_HashCode h_details;
};
@@ -881,7 +1308,7 @@ within the
struct TALER_AmountNBO fee_withdraw;
struct TALER_AmountNBO fee_deposit;
struct TALER_AmountNBO fee_refresh;
- struct GNUNET_HashCode denom_hash;
+ struct TALER_DenominationHash denom_hash;
};
.. _TALER_PaymentResponsePS:
@@ -892,7 +1319,7 @@ within the
* purpose.purpose = TALER_SIGNATURE_MERCHANT_PAYMENT_OK
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_HashCode h_contract_terms;
+ struct TALER_PrivateContractHash h_contract_terms;
};
.. _TALER_ContractPS:
@@ -903,10 +1330,7 @@ within the
* purpose.purpose = TALER_SIGNATURE_MERCHANT_CONTRACT
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct TALER_AmountNBO total_amount;
- struct TALER_AmountNBO max_fee;
- struct GNUNET_HashCode h_contract_terms;
- struct TALER_MerchantPublicKeyP merchant_pub;
+ struct TALER_PrivateContractHash h_contract_terms;
};
.. _TALER_ConfirmWirePS:
@@ -918,10 +1342,10 @@ within the
* purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_HashCode h_wire;
- struct GNUNET_HashCode h_contract_terms;
+ struct TALER_MerchantWireHash h_wire;
+ struct TALER_PrivateContractHash h_contract_terms;
struct TALER_WireTransferIdentifierRawP wtid;
- struct TALER_CoinSpendPublicKeyP coin_pub;
+ union TALER_CoinSpendPublicKeyP coin_pub;
struct GNUNET_TIME_AbsoluteNBO execution_time;
struct TALER_AmountNBO coin_contribution;
};
@@ -934,8 +1358,8 @@ within the
* purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND.
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_HashCode h_contract_terms;
- struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct TALER_PrivateContractHash h_contract_terms;
+ union TALER_CoinSpendPublicKeyP coin_pub;
struct TALER_MerchantPublicKeyP merchant;
uint64_t rtransaction_id;
struct TALER_AmountNBO refund_amount;
@@ -949,10 +1373,10 @@ within the
* purpose.purpose = TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION.
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_HashCode h_contract_terms;
- struct GNUNET_HashCode h_wire;
+ struct TALER_PrivateContractHash h_contract_terms;
+ struct TALER_MerchantWireHash h_wire;
struct TALER_MerchantPublicKeyP merchant;
- struct TALER_CoinSpendPublicKeyP coin_pub;
+ union TALER_CoinSpendPublicKeyP coin_pub;
};
.. _TALER_RefundRequestPS:
@@ -963,9 +1387,8 @@ within the
* purpose.purpose = TALER_SIGNATURE_MERCHANT_REFUND
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_HashCode h_contract_terms;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_MerchantPublicKeyP merchant;
+ struct TALER_PrivateContractHash h_contract_terms;
+ union TALER_CoinSpendPublicKeyP coin_pub;
uint64_t rtransaction_id;
struct TALER_AmountNBO refund_amount;
struct TALER_AmountNBO refund_fee;
@@ -992,10 +1415,10 @@ within the
struct TALER_RecoupRequestPS {
/**
* purpose.purpose = TALER_SIGNATURE_WALLET_COIN_RECOUP
+ * or TALER_SIGNATURE_WALLET_COIN_RECOUP_REFRESH
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct GNUNET_HashCode h_denom_pub;
+ struct TALER_DenominationHash h_denom_pub;
struct TALER_DenominationBlindingKeyP coin_blind;
};
@@ -1009,8 +1432,8 @@ within the
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct GNUNET_TIME_AbsoluteNBO timestamp;
struct TALER_AmountNBO recoup_amount;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_CoinSpendPublicKeyP old_coin_pub;
+ union TALER_CoinSpendPublicKeyP coin_pub;
+ union TALER_CoinSpendPublicKeyP old_coin_pub;
};
.. _TALER_RecoupConfirmationPS:
@@ -1023,7 +1446,7 @@ within the
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct GNUNET_TIME_AbsoluteNBO timestamp;
struct TALER_AmountNBO recoup_amount;
- struct TALER_CoinSpendPublicKeyP coin_pub;
+ union TALER_CoinSpendPublicKeyP coin_pub;
struct TALER_ReservePublicKeyP reserve_pub;
};
@@ -1037,7 +1460,7 @@ within the
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct GNUNET_TIME_AbsoluteNBO timestamp;
- struct GNUNET_HashCode h_denom_pub;
+ struct TALER_DenominationHash h_denom_pub;
};
@@ -1051,7 +1474,7 @@ within the
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct GNUNET_TIME_AbsoluteNBO timestamp;
char operation[8];
- struct GNUNET_HashCode h_denom_pub;
+ struct TALER_DenominationHash h_denom_pub;
};
@@ -1066,7 +1489,7 @@ within the
struct GNUNET_TIME_AbsoluteNBO timestamp;
struct TALER_AmountNBO closing_amount;
struct TALER_ReservePublicKeyP reserve_pub;
- struct GNUNET_HashCode h_wire;
+ struct TALER_PaytoHash h_wire;
};
.. _TALER_CoinLinkSignaturePS:
@@ -1077,15 +1500,13 @@ within the
* purpose.purpose = TALER_SIGNATURE_WALLET_COIN_LINK
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_HashCode h_denom_pub;
- struct TALER_CoinSpendPublicKeyP old_coin_pub;
+ struct TALER_DenominationHash h_denom_pub;
+ union TALER_CoinSpendPublicKeyP old_coin_pub;
struct TALER_TransferPublicKeyP transfer_pub;
- struct GNUNET_HashCode coin_envelope_hash;
+ struct TALER_BlindedCoinHash coin_envelope_hash;
};
-
-
.. _TALER_ReserveStatusRequestSignaturePS:
.. sourcecode:: c
@@ -1135,7 +1556,7 @@ within the
struct TALER_AmountNBO max_deposit_fees;
struct GNUNET_TIME_AbsoluteNBO purse_expiration;
struct GNUNET_TIME_AbsoluteNBO status_timestamp;
- struct GNUNET_HashCode h_contract_terms;
+ struct TALER_PrivateContractHash h_contract_terms;
};
@@ -1144,7 +1565,7 @@ within the
struct TALER_ReserveCloseRequestSignaturePS {
/**
- * purpose.purpose = TALER_SIGNATURE_RESERVE_CLOSE
+ * purpose.purpose = TALER_SIGNATURE_WALLET_RESERVE_CLOSE
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
};
@@ -1162,12 +1583,13 @@ within the
struct TALER_PurseRequestSignaturePS {
/**
- * purpose.purpose = TALER_SIGNATURE_PURSE_REQUEST
+ * purpose.purpose = TALER_SIGNATURE_WALLET_PURSE_CREATE
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct GNUNET_TIME_AbsoluteNBO purse_expiration;
struct TALER_AmountNBO merge_value_after_fees;
- struct GNUNET_HashCode h_contract_terms;
+ struct TALER_PrivateContractHashP h_contract_terms;
+ uint32_t min_age;
};
@@ -1180,9 +1602,23 @@ within the
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct TALER_AmountNBO coin_contribution;
- struct GNUNET_TIME_AbsoluteNBO purse_expiration;
- struct TALER_PursePublicKey purse_pub;
- struct GNUNET_HashCode h_contract_terms;
+ struct TALER_DenominationHash h_denom_pub;
+ struct TALER_AgeCommitmentHash h_age_commitment;
+ struct TALER_PursePublicKeyP purse_pub;
+ struct GNUNET_HashCode h_exchange_base_url;
+ };
+
+
+.. _TALER_ReserveOpenDepositSignaturePS:
+.. sourcecode:: c
+
+ struct TALER_PurseDepositSignaturePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_WALLET_RESERVE_OPEN_DEPOSIT
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct TALER_ReserveSignatureP reserve_sig;
+ struct TALER_AmountNBO coin_contribution;
};
@@ -1196,9 +1632,9 @@ within the
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct TALER_AmountNBO total_purse_amount;
struct TALER_AmountNBO total_deposit_fees;
- struct TALER_PursePublicKey purse_pub;
+ struct TALER_PursePublicKeyP purse_pub;
struct GNUNET_TIME_AbsoluteNBO purse_expiration;
- struct GNUNET_HashCode h_contract_terms;
+ struct TALER_PrivateContractHashP h_contract_terms;
};
.. _TALER_PurseMergeSignaturePS:
@@ -1206,15 +1642,11 @@ within the
struct TALER_PurseMergeSignaturePS {
/**
- * purpose.purpose = TALER_SIGNATURE_PURSE_MERGE
+ * purpose.purpose = TALER_SIGNATURE_WALLET_PURSE_MERGE
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct TALER_ReservePublicKey reserve_pub;
struct GNUNET_TIME_AbsoluteNBO merge_timestamp;
- struct GNUNET_TIME_AbsoluteNBO purse_expiration;
- struct TALER_AmountNBO merge_value_after_fees;
- struct GNUNET_HashCode h_contract_terms;
- struct GNUNET_HashCode h_wire;
+ struct TALER_PaytoHashP h_wire;
};
@@ -1223,59 +1655,58 @@ within the
struct TALER_AccountMergeSignaturePS {
/**
- * purpose.purpose = TALER_SIGNATURE_ACCOUNT_MERGE
+ * purpose.purpose = TALER_SIGNATURE_WALLET_ACCOUNT_MERGE
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct TALER_PursePublicKey purse_pub;
+ struct TALER_ReservePublicKeyP reserve_pub;
+ struct TALER_PursePublicKeyP purse_pub;
+ struct TALER_AmountNBO merge_amount_after_fees;
struct GNUNET_TIME_AbsoluteNBO merge_timestamp;
struct GNUNET_TIME_AbsoluteNBO purse_expiration;
- struct TALER_AmountNBO merge_value_after_fees;
- struct GNUNET_HashCode h_contract_terms;
- struct GNUNET_HashCode h_wire;
+ struct TALER_PrivateContractHashP h_contract_terms;
+ uint32_t min_age;
};
-
-.. _TALER_PurseMergeSuccessSignaturePS:
+.. _TALER_AccountSetupRequestSignaturePS:
.. sourcecode:: c
- struct TALER_PurseMergeSuccessSignaturePS {
+ struct TALER_AccountSetupRequestSignaturePS {
/**
- * purpose.purpose = TALER_SIGNATURE_PURSE_MERGE_SUCCESS
+ * purpose.purpose = TALER_SIGNATURE_WALLET_ACCOUNT_SETUP
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct TALER_ReservePublicKey reserve_pub;
- struct TALER_PursePublicKey purse_pub;
- struct TALER_AmountNBO merge_amount_after_fees;
- struct GNUNET_TIME_AbsoluteNBO contract_time;
- struct GNUNET_HashCode h_contract_terms;
- struct GNUNET_HashCode h_wire;
+ struct TALER_AmountNBO threshold;
};
-
-.. _TALER_AccountSetupRequestSignaturePS:
+.. _TALER_AccountSetupSuccessSignaturePS:
.. sourcecode:: c
- struct TALER_AccountSetupRequestSignaturePS {
+ struct TALER_AccountSetupSuccessSignaturePS {
/**
- * purpose.purpose = TALER_SIGNATURE_ACCOUNT_SETUP_REQUEST
+ * purpose.purpose = TALER_SIGNATURE_WALLET_ACCOUNT_SETUP_SUCCESS
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_TIME_AbsoluteNBO kyc_timestamp;
- struct TALER_AmountNBO kyc_fee;
- struct GNUNET_HashCode h_wire;
+ struct TALER_PaytoHash h_payto;
+ struct GNUNET_HashCode h_kyc;
+ struct GNUNET_TIME_AbsoluteNBO timestamp;
};
-.. _TALER_AccountSetupSuccessSignaturePS:
+.. _TALER_PurseMergeSuccessSignaturePS:
.. sourcecode:: c
- struct TALER_AccountSetupRequestSignaturePS {
+ struct TALER_PurseMergeSuccessSignaturePS {
/**
- * purpose.purpose = TALER_SIGNATURE_ACCOUNT_SETUP_SUCCESS
+ * purpose.purpose = TALER_SIGNATURE_PURSE_MERGE_SUCCESS
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct TALER_ReservePublicKey reserve_pub;
- struct GNUNET_TIME_AbsoluteNBO now;
+ struct TALER_ReservePublicKeyP reserve_pub;
+ struct TALER_PursePublicKeyP purse_pub;
+ struct TALER_AmountNBO merge_amount_after_fees;
+ struct GNUNET_TIME_AbsoluteNBO contract_time;
+ struct TALER_PrivateContractHashP h_contract_terms;
+ struct TALER_PaytoHashP h_wire;
+ uint32_t min_age;
};
@@ -1339,10 +1770,8 @@ within the
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct TALER_PursePublicKey purse_pub;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_MerchantPublicKeyP merchant;
- struct TALER_AmountNBO remaining_amount;
- struct TALER_AmountNBO purse_fee_share;
+ union TALER_CoinSpendPublicKeyP coin_pub;
+ struct TALER_AmountNBO refunded_amount;
struct TALER_AmountNBO refund_fee;
};
@@ -1355,7 +1784,7 @@ within the
* purpose.purpose = TALER_SIGNATURE_SM_DENOMINATION_KEY
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_HashCode h_denom_pub;
+ struct TALER_DenominationHash h_denom_pub;
struct GNUNET_HashCode h_section_name;
struct GNUNET_TIME_AbsoluteNBO anchor_time;
struct GNUNET_TIME_RelativeNBO duration_withdraw;
@@ -1383,7 +1812,7 @@ within the
* purpose.purpose = TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED.
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_HashCode h_denom_pub;
+ struct TALER_DenominationHash h_denom_pub;
};
@@ -1433,7 +1862,10 @@ within the
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct GNUNET_TIME_AbsoluteNBO start_date;
- struct GNUNET_HashCode h_wire GNUNET_PACKED;
+ struct TALER_PaytoHash h_wire;
+ struct GNUNET_HashCode h_conversion_url;
+ struct GNUNET_HashCode h_credit_restrictions;
+ struct GNUNET_HashCode h_debit_restrictions;
};
.. _TALER_MasterDelWirePS:
@@ -1445,5 +1877,104 @@ within the
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct GNUNET_TIME_AbsoluteNBO end_date;
- struct GNUNET_HashCode h_wire GNUNET_PACKED;
+ struct TALER_PaytoHash h_wire;
+ };
+
+
+.. _TALER_MasterAmlOfficerStatusPS:
+.. sourcecode:: c
+
+ struct TALER_MasterAmlOfficerStatusPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_MASTER_AML_KEY
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_TIME_TimestampNBO change_date;
+ struct TALER_AmlOfficerPublicKeyP officer_pub;
+ struct GNUNET_HashCode h_officer_name GNUNET_PACKED;
+ uint32_t is_active GNUNET_PACKED;
+ };
+
+.. _TALER_AmlDecisionPS:
+.. sourcecode:: c
+
+ struct TALER_AmlDecisionPS {
+ /**
+ * purpose.purpose =TALER_SIGNATURE_AML_DECISION.
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_HashCode h_justification GNUNET_PACKED;
+ struct GNUNET_TIME_TimestampNBO decision_time;
+ struct TALER_AmountNBO new_threshold;
+ struct TALER_PaytoHashP h_payto GNUNET_PACKED;
+ struct GNUNET_HashCode h_kyc_requirements;
+ uint32_t new_state GNUNET_PACKED;
+ };
+
+.. _TALER_PartnerConfigurationPS:
+.. sourcecode:: c
+
+ struct TALER_PartnerConfigurationPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_MASTER_PARNTER_DETAILS
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct TALER_MasterPublicKeyP partner_pub;
+ struct GNUNET_TIME_TimestampNBO start_date;
+ struct GNUNET_TIME_TimestampNBO end_date;
+ struct GNUNET_TIME_RelativeNBO wad_frequency;
+ struct TALER_AmountNBO wad_fee;
+ struct GNUNET_HashCode h_url;
+ };
+
+.. _TALER_ReserveOpenPS:
+.. sourcecode:: c
+
+ struct TALER_ReserveOpenPS {
+ /**
+ * Purpose.purpose = TALER_SIGNATURE_WALLET_RESERVE_OPEN
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct TALER_AmountNBO reserve_payment;
+ struct GNUNET_TIME_TimestampNBO request_timestamp;
+ struct GNUNET_TIME_TimestampNBO reserve_expiration;
+ uint32_t purse_limit;
+ };
+
+.. _TALER_ReserveClosePS:
+.. sourcecode:: c
+
+ struct TALER_ReserveClosePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_WALLET_RESERVE_CLOSE
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_TIME_TimestampNBO request_timestamp;
+ struct TALER_PaytoHashP target_account_h_payto;
+ };
+
+.. _TALER_WalletReserveAttestRequestSignaturePS:
+.. sourcecode:: c
+
+ struct TALER_ReserveAttestRequestPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_WALLET_ATTEST_REQUEST
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_TIME_TimestampNBO request_timestamp;
+ struct GNUNET_HashCode h_details;
+ };
+
+.. _TALER_ExchangeAttestPS:
+.. sourcecode:: c
+
+ struct TALER_ExchangeAttestPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_EXCHANGE_RESERVE_ATTEST_DETAILS
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_TIME_TimestampNBO attest_timestamp;
+ struct GNUNET_TIME_TimestampNBO expiration_time;
+ struct TALER_ReservePublicKeyP reserve_pub;
+ struct GNUNET_HashCode h_attributes;
};
diff --git a/core/api-corebank.rst b/core/api-corebank.rst
new file mode 100644
index 00000000..680b2724
--- /dev/null
+++ b/core/api-corebank.rst
@@ -0,0 +1,1244 @@
+..
+ This file is part of GNU TALER.
+
+ Copyright (C) 2014-2024 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+.. target audience: developer, core developer
+
+.. _corebank-api:
+
+====================
+Taler Core Bank API
+====================
+
+.. contents:: Table of Contents
+ :local:
+
+Introduction
+------------
+
+The Libeufin bank provides a minimal core banking system. In addition to that,
+it provides features for local/regional currencies.
+
+Authentication
+--------------
+
+Some requests require the client to authenticate via HTTP Basic auth (RFC 7617)
+or using a bearer token which can be obtained or refreshed from the
+``/accounts/$USERNAME/token`` endpoint.
+When using Basic authentication, the user-id must be the bank
+username, and the password the password for the corresponding user.
+
+Another way to obtain a login token is by manually configuring it for certain
+endpoints. For example, the exchange could give an auditor read-only access to
+the taler-wire-gateway facade via such a manually configured access token.
+
+The ``admin`` user is a special, hard-coded username. Some requests require the
+client to authenticate as the admin.
+
+.. http:post:: /accounts/$USERNAME/token
+
+ See :ref:`DD 48 token endpoint <dd48-token>`.
+
+
+Bank Web UI
+-----------
+
+The web UI for the bank is typically served under ``/``.
+
+Config
+------
+
+.. http:get:: /config
+
+ Return the protocol version and configuration information about the bank.
+ This specification corresponds to ``current`` protocol being version **4**.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ Response is a `Config`.
+
+ **Details:**
+
+ .. ts:def:: Config
+
+ interface Config {
+ // Name of the API.
+ name: "taler-corebank";
+
+ // libtool-style representation of the Bank protocol version, see
+ // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
+ // The format is "current:revision:age".
+ version: string;
+
+ // Bank display name to be used in user interfaces.
+ // For consistency use "Taler Bank" if missing.
+ // @since v4, will become mandatory in the next version.
+ bank_name?: string;
+
+ // Advertised base URL to use when you sharing an URL with another
+ // program.
+ // @since v4.
+ base_url?: string;
+
+ // If 'true' the server provides local currency conversion support
+ // If 'false' some parts of the API are not supported and return 501
+ allow_conversion: boolean;
+
+ // If 'true' anyone can register
+ // If 'false' only admin can
+ allow_registrations: boolean;
+
+ // If 'true' account can delete themselves
+ // If 'false' only admin can delete accounts
+ allow_deletions: boolean;
+
+ // If 'true' anyone can edit their name
+ // If 'false' only admin can
+ allow_edit_name: boolean;
+
+ // If 'true' anyone can edit their cashout account
+ // If 'false' only admin can
+ allow_edit_cashout_payto_uri: boolean;
+
+ // Default debt limit for newly created accounts
+ default_debit_threshold: Amount;
+
+ // Currency used by this bank.
+ currency: string;
+
+ // How the bank SPA should render this currency.
+ currency_specification: CurrencySpecification;
+
+ // TAN channels supported by the server
+ supported_tan_channels: TanChannel[];
+
+ // Wire transfer type supported by the bank.
+ // Default to 'iban' is missing
+ // @since v4, will become mandatory in the next version.
+ wire_type?: string;
+ }
+
+
+Account Management
+------------------
+
+.. _bank-account-register:
+
+.. http:post:: /accounts
+
+ Create a new bank account. Depending on the configuration,
+ the account creation is self-serve, or only restricted to
+ the administrators.
+
+ **Request:**
+
+ .. ts:def:: RegisterAccountRequest
+
+ interface RegisterAccountRequest {
+ // Username of the account
+ username: string;
+
+ // Password of the account used for authentication
+ password: string;
+
+ // Legal name of the account owner
+ name: string;
+
+ // Make this account visible to anyone?
+ // Defaults to false.
+ is_public?: boolean;
+
+ // Make this account a taler exchange account?
+ // If true:
+ // - incoming transactions to the account that do not
+ // have a valid reserve public key are automatically
+ // - the account provides the taler-wire-gateway-api endpoints
+ // Defaults to false.
+ is_taler_exchange?: boolean;
+
+ // Addresses where to send the TAN for protected operations.
+ contact_data?: ChallengeContactData;
+
+ // IBAN 'payto' URI of a fiat bank account with a 'receiver-name' parameter.
+ // If 'receiver-name' is missing, ``name`` will be used instead.
+ // Payments will be sent to this bank account
+ // when the user wants to convert the regional currency
+ // back to fiat currency outside bank.
+ cashout_payto_uri?: string;
+
+ // Internal payto URI of this bank account.
+ // Used mostly for testing, this field is ignored if the bank payment
+ // method is not IBAN.
+ payto_uri?: string;
+
+ // If present, set the max debit allowed for this user
+ // Only admin can set this property.
+ debit_threshold?: Amount;
+
+ // If present, enables 2FA and set the TAN channel used for challenges
+ // Only admin can set this property, other user can reconfig their account
+ // after creation.
+ tan_channel?: TanChannel;
+ }
+
+ .. ts:def:: ChallengeContactData
+
+ interface ChallengeContactData {
+ // E-Mail address
+ email?: EmailAddress;
+
+ // Phone number.
+ phone?: PhoneNumber;
+ }
+
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ Response is a `RegisterAccountResponse`.
+ :http:statuscode:`400 Bad request`:
+ Input data was invalid. For example, the client specified a invalid
+ phone number or e-mail address.
+ :http:statuscode:`401 Unauthorized`:
+ Invalid credentials or missing rights.
+ :http:statuscode:`409 Conflict`:
+ * ``TALER_EC_BANK_REGISTER_USERNAME_REUSE`` : username already used.
+ * ``TALER_EC_BANK_REGISTER_PAYTO_URI_REUSE`` : payto URI already used.
+ * ``TALER_EC_BANK_UNALLOWED_DEBIT`` : admin account does not have sufficient funds to grant bonus.
+ * ``TALER_EC_BANK_RESERVED_USERNAME_CONFLICT`` : a reserved username was attempted, like ``admin`` or ``bank``
+ * ``TALER_EC_BANK_NON_ADMIN_PATCH_DEBT_LIMIT`` : a non-admin user has tried to create an account with a customer debt limit.
+ * ``TALER_EC_BANK_NON_ADMIN_SET_TAN_CHANNEL`` : a non-admin user has tried to create an account with 2fa.
+ * ``TALER_EC_BANK_TAN_CHANNEL_NOT_SUPPORTED``: ``tan_channel`` is not supported, check bank config to find supported ones.
+ * ``TALER_EC_BANK_MISSING_TAN_INFO``: the user did not share any contact data where to send the TAN via ``tan_channel``.
+
+ **Details:**
+
+ .. ts:def:: RegisterAccountResponse
+
+ interface RegisterAccountResponse {
+ // Internal payto URI of this bank account.
+ internal_payto_uri: string;
+ }
+
+.. _delete-account:
+
+.. http:delete:: /accounts/$USERNAME
+
+ Delete the account whose username is ``$USERNAME``. The deletion
+ succeeds only if the balance is *zero*. Typically only available to
+ the administrator, but can be configured to allow ordinary users too.
+
+ **Response:**
+
+ :http:statuscode:`202 Accepted`:
+ 2FA is required for this operation. This returns the `Challenge` response.
+ :http:statuscode:`204 No content`:
+ The account was successfully deleted.
+ :http:statuscode:`401 Unauthorized`:
+ Invalid credentials or missing rights.
+ :http:statuscode:`404 Not found`:
+ The account pointed by ``$USERNAME`` was not found.
+ :http:statuscode:`409 Conflict`:
+ * ``TALER_EC_BANK_RESERVED_USERNAME_CONFLICT`` : a reserved username was attempted, like ``admin`` or ``bank``.
+ * ``TALER_EC_BANK_ACCOUNT_BALANCE_NOT_ZERO``: the account balance was not zero.
+
+.. _account-reconfig:
+
+.. http:patch:: /accounts/$USERNAME
+
+ Allows reconfiguring the account data of ``$USERNAME``.
+
+ **Request:**
+
+ .. ts:def:: AccountReconfiguration
+
+ interface AccountReconfiguration {
+ // Addresses where to send the TAN for protected operations.
+ contact_data?: ChallengeContactData;
+
+ // IBAN 'payto' URI of a fiat bank account with a 'receiver-name' parameter.
+ // If 'receiver-name' is missing, ``name`` will be used instead.
+ // Payments will be sent to this bank account
+ // when the user wants to convert the regional currency
+ // back to fiat currency outside bank.
+ // Only admin can change this property if not allowed in config
+ cashout_payto_uri?: string;
+
+ // If present, change the legal name associated with $username.
+ // Only admin can change this property if not allowed in config
+ name?: string;
+
+ // Make this account visible to anyone?
+ is_public?: boolean;
+
+ // If present, change the max debit allowed for this user
+ // Only admin can change this property.
+ debit_threshold?: Amount;
+
+ // If present, enables 2FA and set the TAN channel used for challenges
+ tan_channel?: TanChannel;
+ }
+
+ **Response:**
+
+ :http:statuscode:`202 Accepted`:
+ 2FA is required for this operation. This returns the `Challenge` response.
+ :http:statuscode:`204 No content`:
+ Operation successful.
+ :http:statuscode:`401 Unauthorized`:
+ Invalid credentials or missing rights.
+ :http:statuscode:`404 Not found`:
+ The account pointed by ``$USERNAME`` was not found.
+ :http:statuscode:`409 Conflict`:
+ * ``TALER_EC_BANK_NON_ADMIN_PATCH_LEGAL_NAME`` : a non-admin user has tried to change their legal name.
+ * ``TALER_EC_BANK_NON_ADMIN_PATCH_CASHOUT`` : a non-admin user has tried to change their cashout account.
+ * ``TALER_EC_BANK_NON_ADMIN_PATCH_DEBT_LIMIT`` : a non-admin user has tried to change their debt limit.
+ * ``TALER_EC_BANK_TAN_CHANNEL_NOT_SUPPORTED`` : ``tan_channel`` is not supported, check bank config to find supported ones.
+ * ``TALER_EC_BANK_MISSING_TAN_INFO`` : the user did not share any contact data where to send the TAN via ``tan_channel``.
+
+
+.. _account-password-reconfig:
+
+.. http:patch:: /accounts/$USERNAME/auth
+
+ Allows changing the account's password.
+
+
+ **Request:**
+
+ .. ts:def:: AccountPasswordChange
+
+ interface AccountPasswordChange {
+ // Old password. If present it need to match the current
+ // password before updating.
+ old_password?: string;
+ // New password.
+ new_password: string;
+ }
+
+ **Response:**
+
+ :http:statuscode:`202 Accepted`:
+ 2FA is required for this operation. This returns the `Challenge` response.
+ :http:statuscode:`204 No content`:
+ Operation successful.
+ :http:statuscode:`404 Not found`:
+ The account pointed by ``$USERNAME`` was not found.
+ :http:statuscode:`401 Unauthorized`:
+ Invalid credentials or missing rights.
+ :http:statuscode:`409 Conflict`:
+ * ``TALER_EC_BANK_NON_ADMIN_PATCH_MISSING_OLD_PASSWORD``: a non-admin user has tried to change their password whihout providing the current one.
+ * ``TALER_EC_BANK_PATCH_BAD_OLD_PASSWORD`` : provided old password does not match current password.
+
+.. _account-list:
+
+.. http:get:: /public-accounts
+
+ Show those accounts whose histories are publicly visible. For example,
+ accounts from donation receivers. As such, this request is unauthenticated.
+
+
+ **Request:**
+
+ :query delta: *Optional.*
+ Takes value of the form ``N (-N)``, so that at most ``N`` values strictly older (younger) than ``start`` are returned. Defaults to ``-20`` to return the last 20 entries.
+ :query start: *Optional.*
+ Row number threshold, see ``delta`` for its interpretation. Defaults to smallest or biggest row id possible according to ``delta`` sign.
+ :query filter_name: *Optional.*
+ Pattern to filter on the account legal name. Given
+ the filter 'foo', all the results will **contain**
+ 'foo' in their legal name. Without this option,
+ all the existing accounts are returned.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ Response is a `PublicAccountsResponse`.
+ :http:statuscode:`204 No content`:
+ No public account.
+
+ **Details:**
+
+ .. ts:def:: PublicAccountsResponse
+
+ interface PublicAccountsResponse {
+ public_accounts: PublicAccount[];
+ }
+
+ .. ts:def:: PublicAccount
+
+ interface PublicAccount {
+ // Username of the account
+ username: string;
+
+ // Internal payto URI of this bank account.
+ payto_uri: string;
+
+ // Current balance of the account
+ balance: Balance;
+
+ // Is this a taler exchange account?
+ is_taler_exchange: boolean;
+
+ // Opaque unique ID used for pagination.
+ // @since v4, will become mandatory in the next version.
+ row_id?: Integer;
+ }
+
+.. http:get:: /accounts
+
+ Obtains a list of the accounts registered at the bank.
+ It returns only the information that this API handles, without
+ any balance or transactions list.
+ This request is only available to the administrator.
+
+ **Request:**
+
+ :query delta: *Optional.*
+ Takes value of the form ``N (-N)``, so that at most ``N`` values strictly older (younger) than ``start`` are returned. Defaults to ``-20`` to return the last 20 entries.
+ :query start: *Optional.*
+ Row number threshold, see ``delta`` for its interpretation. Defaults to smallest or biggest row id possible according to ``delta`` sign.
+ :query filter_name: *Optional.*
+ Pattern to filter on the account legal name. Given
+ the filter 'foo', all the results will **contain**
+ 'foo' in their legal name. Without this option,
+ all the existing accounts are returned.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ At least one account was found.
+ The server responds with a `ListBankAccountsResponse` object.
+ :http:statuscode:`204 No Content`:
+ No accounts were found for the given request.
+ :http:statuscode:`401 Unauthorized`:
+ Invalid credentials or missing rights.
+
+ **Details:**
+
+ .. ts:def:: ListBankAccountsResponse
+
+ interfaces ListBankAccountsResponse {
+ accounts: AccountMinimalData[];
+ }
+
+ .. ts:def:: Balance
+
+ interface Balance {
+ amount: Amount;
+ credit_debit_indicator: "credit" | "debit";
+ }
+
+ .. ts:def:: AccountMinimalData
+
+ interface AccountMinimalData {
+ // Username of the account
+ username: string;
+
+ // Legal name of the account owner.
+ name: string;
+
+ // Internal payto URI of this bank account.
+ payto_uri: string;
+
+ // Current balance of the account
+ balance: Balance;
+
+ // Number indicating the max debit allowed for the requesting user.
+ debit_threshold: Amount;
+
+ // Is this account visible to anyone?
+ is_public: boolean;
+
+ // Is this a taler exchange account?
+ is_taler_exchange: boolean;
+
+ // Opaque unique ID used for pagination.
+ // @since v4, will become mandatory in the next version.
+ row_id?: Integer;
+
+ // Current status of the account
+ // active: the account can be used
+ // deleted: the account has been deleted but is retained for compliance
+ // reasons, only the administrator can access it
+ // Default to 'active' is missing
+ // @since v4, will become mandatory in the next version.
+ status?: "active" | "deleted";
+ }
+
+.. _bank-account-info:
+
+.. http:get:: /accounts/$USERNAME
+
+ Obtains information relative to the account owned by
+ ``$USERNAME``. The request is available to the administrator
+ and ``$USERNAME`` itself.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The bank responds with an `AccountData` object.
+ :http:statuscode:`401 Unauthorized`:
+ Invalid credentials or missing rights.
+ :http:statuscode:`404 Not found`:
+ The account pointed by ``$USERNAME`` was not found.
+
+ **Details:**
+
+ .. ts:def:: AccountData
+
+ interface AccountData {
+ // Legal name of the account owner.
+ name: string;
+
+ // Available balance on the account.
+ balance: Balance;
+
+ // payto://-URI of the account.
+ payto_uri: string;
+
+ // Number indicating the max debit allowed for the requesting user.
+ debit_threshold: Amount;
+
+ // Addresses where to send the TAN for transactions.
+ // Currently only used for cashouts.
+ // If missing, cashouts will fail.
+ // In the future, might be used for other transactions
+ // as well.
+ contact_data?: ChallengeContactData;
+
+ // IBAN 'payto' URI with a 'receiver-name' parameter of a fiat bank
+ // account where to send cashouts. This field is optional
+ // because not all the accounts are required to participate
+ // in the merchants' circuit. One example is the exchange:
+ // that never cashouts. Registering these accounts can
+ // be done via the access API.
+ cashout_payto_uri?: string;
+
+ // Is this account visible to anyone?
+ is_public: boolean;
+
+ // Is this a taler exchange account?
+ is_taler_exchange: boolean;
+
+ // Is 2FA enabled and what channel is used for challenges?
+ tan_channel?: TanChannel;
+
+ // Current status of the account
+ // active: the account can be used
+ // deleted: the account has been deleted but is retained for compliance
+ // reasons, only the administrator can access it
+ // Default to 'active' is missing
+ // @since v4, will become mandatory in the next version.
+ status?: "active" | "deleted";
+ }
+
+Transactions
+------------
+
+.. http:get:: /accounts/$USERNAME/transactions
+
+ Retrieve a subset of transactions related to $USERNAME.
+
+ The list of returned transactions is determined by a row ID *starting point*
+ and a signed non-zero integer *delta*:
+
+ * If *delta* is positive, return a list of up to *delta* transactions (all matching
+ the filter criteria) strictly **after** the starting point. The transactions are sorted
+ in **ascending** order of the row ID.
+ * If *delta* is negative, return a list of up to *-delta* transactions (all matching
+ the filter criteria) strictly **before** the starting point. The transactions are sorted
+ in **descending** order of the row ID.
+
+ If *starting point* is not explicitly given, it defaults to:
+
+ * A value that is **smaller** than all other row IDs if *delta* is **positive**.
+ * A value that is **larger** than all other row IDs if *delta* is **negative**.
+
+ **Request:**
+
+ :query delta: *Optional.*
+ Takes value of the form ``N (-N)``, so that at most ``N`` values strictly older (younger) than ``start`` are returned. Defaults to ``-20`` to return the last 20 entries.
+ :query start: *Optional.*
+ Row number threshold, see ``delta`` for its interpretation. Defaults to smallest or biggest row id possible according to ``delta`` sign.
+ :query long_poll_ms: Optional number to express how many milliseconds the server
+ should wait for at least one result to be shown. If not given, the server
+ responds immediately, regardless of the result.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The bank responds with an `BankAccountTransactionsResponse` object.
+ :http:statuscode:`204 No content`:
+ No transaction found.
+ :http:statuscode:`401 Unauthorized`:
+ Invalid credentials or missing rights.
+ :http:statuscode:`404 Not found`:
+ The account pointed by ``$USERNAME`` was not found.
+
+ **Details:**
+
+ .. ts:def:: BankAccountTransactionsResponse
+
+ interface BankAccountTransactionsResponse {
+ transactions: BankAccountTransactionInfo[];
+ }
+
+.. http:get:: /accounts/$USERNAME/transactions/$TRANSACTION_ID
+
+ Retrieve the transaction whose identifier is ``TRANSACTION_ID``.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The bank responds with an `BankAccountTransactionInfo` object.
+ :http:statuscode:`401 Unauthorized`:
+ Invalid credentials or missing rights.
+ :http:statuscode:`404 Not found`:
+ The account pointed by ``$USERNAME`` was not found.
+
+ **Details:**
+
+ .. ts:def:: BankAccountTransactionInfo
+
+ interface BankAccountTransactionInfo {
+ creditor_payto_uri: string;
+ debtor_payto_uri: string;
+
+ amount: Amount;
+ direction: "debit" | "credit";
+
+ subject: string;
+
+ // Transaction unique ID. Matches
+ // $TRANSACTION_ID from the URI.
+ row_id: Integer;
+ date: Timestamp;
+ }
+
+.. http:post:: /accounts/$USERNAME/transactions
+
+ Create a new transaction where the bank account with the label ``USERNAME`` is **debited**.
+
+ **Request:**
+
+ .. ts:def:: CreateTransactionRequest
+
+ interface CreateTransactionRequest {
+ // Address in the Payto format of the wire transfer receiver.
+ // It needs at least the 'message' query string parameter.
+ payto_uri: string;
+
+ // Transaction amount (in the $currency:x.y format), optional.
+ // However, when not given, its value must occupy the 'amount'
+ // query string parameter of the 'payto' field. In case it
+ // is given in both places, the payto_uri's takes the precedence.
+ amount: string;
+
+ // Nonce to make the request idempotent. Requests with the same
+ // ``request_uid`` that differ in any of the other fields
+ // are rejected.
+ // @since v4, will become mandatory in the next version.
+ request_uid?: ShortHashCode;
+ }
+
+ **Response:**
+
+ :http:statuscode:`200 Ok`:
+ The bank responds with an `CreateTransactionResponse` object.
+ :http:statuscode:`202 Accepted`:
+ 2FA is required for this operation. This returns the `Challenge` response.
+ :http:statuscode:`400 Bad Request`:
+ The request was invalid or the payto://-URI used unacceptable features.
+ :http:statuscode:`401 Unauthorized`:
+ Invalid credentials.
+ :http:statuscode:`404 Not found`:
+ The account pointed by ``$USERNAME`` was not found.
+ :http:statuscode:`409 Conflict`:
+ * ``TALER_EC_BANK_SAME_ACCOUNT`` : creditor account is the same than ``USERNAME``.
+ * ``TALER_EC_BANK_UNKNOWN_CREDITOR`` : creditor account was not found.
+ * ``TALER_EC_BANK_UNALLOWED_DEBIT`` : the account does not have sufficient funds.
+ * ``TALER_EC_BANK_TRANSFER_REQUEST_UID_REUSED``: an operation with the same ``request_uid`` but different details has been submitted before.
+
+ **Details:**
+
+ .. ts:def:: CreateTransactionResponse
+
+ interface CreateTransactionResponse {
+ // ID identifying the transaction being created
+ row_id: Integer;
+ }
+
+Taler Withdrawals
+-----------------
+
+.. http:post:: /accounts/$USERNAME/withdrawals
+
+ Create a withdrawal operation, resulting in a ``taler://withdraw`` URI.
+
+ **Request:**
+
+ .. ts:def:: BankAccountCreateWithdrawalRequest
+
+ interface BankAccountCreateWithdrawalRequest {
+ // Amount to withdraw.
+ amount: Amount;
+ }
+
+ **Response:**
+
+ :http:statuscode:`200 Ok`:
+ The bank responds with an `BankAccountCreateWithdrawalResponse` object.
+ :http:statuscode:`404 Not found`:
+ The account pointed by ``$USERNAME`` was not found.
+ :http:statuscode:`409 Conflict`:
+ The account does not have sufficient funds.
+
+ **Details:**
+
+ .. ts:def:: BankAccountCreateWithdrawalResponse
+
+ interface BankAccountCreateWithdrawalResponse {
+ // ID identifying the operation being created
+ withdrawal_id: string;
+
+ // URI that can be passed to the wallet to initiate the withdrawal
+ taler_withdraw_uri: string;
+ }
+
+.. http:post:: /accounts/$USERNAME/withdrawals/$WITHDRAWAL_ID/confirm
+
+ Confirms ``WITHDRAWAL_ID`` operation. Has no effect on an already confirmed
+ withdrawal operation. This call is responsible for wiring the funds to the
+ exchange.
+
+ **Response:**
+
+ :http:statuscode:`202 Accepted`:
+ 2FA is required for this operation. This returns the `Challenge` response.
+ :http:statuscode:`204 No content`:
+ The withdrawal operation has been confirmed.
+ :http:statuscode:`404 Not found`:
+ The operation was not found.
+ :http:statuscode:`409 Conflict`:
+ * ``TALER_EC_BANK_CONFIRM_ABORT_CONFLICT`` : the withdrawal has been aborted previously and can't be confirmed.
+ * ``TALER_EC_BANK_CONFIRM_INCOMPLETE`` : the withdraw operation cannot be confirmed because no exchange and reserve public key selection happened before.
+ * ``TALER_EC_BANK_UNALLOWED_DEBIT`` : the account does not have sufficient funds.
+
+.. http:post:: /accounts/$USERNAME/withdrawals/$WITHDRAWAL_ID/abort
+
+ Aborts ``WITHDRAWAL_ID`` operation. Has no effect on an already aborted
+ operation.
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The withdrawal operation has been aborted.
+ :http:statuscode:`404 Not found`:
+ The withdrawal operation was not found.
+ :http:statuscode:`409 Conflict`:
+ The withdrawal operation has been confirmed previously and can't be aborted.
+
+.. http:get:: /withdrawals/$WITHDRAWAL_ID
+
+ Retrieve public information about ``WITHDRAWAL_ID`` withdrawal operation.
+ Does not require further authentication as knowledge of ``WITHDRAWAL_ID``
+ serves as an authenticator.
+
+ **Request:**
+
+ :query long_poll_ms:
+ *Optional.* If specified, the bank will wait up to ``long_poll_ms``
+ milliseconds for operationt state to be different from ``old_state`` before sending the HTTP
+ response. A client must never rely on this behavior, as the bank may
+ return a response immediately.
+ :query old_state:
+ *Optional.* Default to "pending".
+
+ **Response:**
+
+ :http:statuscode:`200 Ok`:
+ The bank responds with an `WithdrawalPublicInfo` object.
+ :http:statuscode:`404 Not found`:
+ The operation was not found.
+
+ **Details:**
+
+ .. ts:def:: WithdrawalPublicInfo
+
+ interface WithdrawalPublicInfo {
+ // Current status of the operation
+ // pending: the operation is pending parameters selection (exchange and reserve public key)
+ // selected: the operations has been selected and is pending confirmation
+ // aborted: the operation has been aborted
+ // confirmed: the transfer has been confirmed and registered by the bank
+ status: "pending" | "selected" | "aborted" | "confirmed";
+
+ // Amount that will be withdrawn with this operation
+ // (raw amount without fee considerations).
+ amount: Amount;
+
+ // Account username
+ username: string;
+
+ // Reserve public key selected by the exchange,
+ // only non-null if ``status`` is ``selected`` or ``confirmed``.
+ selected_reserve_pub?: string;
+
+ // Exchange account selected by the wallet
+ // only non-null if ``status`` is ``selected`` or ``confirmed``.
+ selected_exchange_account?: string;
+ }
+
+Cashouts
+--------
+
+.. _account-cashout:
+
+.. http:post:: /accounts/$USERNAME/cashouts
+
+ Initiates a conversion to fiat currency. The fiat
+ bank account to be
+ credited is the one specified at registration time via the
+ *cashout_payto_uri* parameter. The regional bank account
+ is specified via ``$USERNAME``.
+
+ .. note::
+
+ Consult the `cashout rates call <cashout-rates_>`_ to learn
+ about any applicable fee or exchange rate.
+
+
+ **Request:**
+
+ .. ts:def:: CashoutRequest
+
+ interface CashoutRequest {
+ // Nonce to make the request idempotent. Requests with the same
+ // ``request_uid`` that differ in any of the other fields
+ // are rejected.
+ request_uid: ShortHashCode;
+
+ // Optional subject to associate to the
+ // cashout operation. This data will appear
+ // as the incoming wire transfer subject in
+ // the user's fiat bank account.
+ subject?: string;
+
+ // That is the plain amount that the user specified
+ // to cashout. Its $currency is the (regional) currency of the
+ // bank instance.
+ amount_debit: Amount;
+
+ // That is the amount that will effectively be
+ // transferred by the bank to the user's fiat bank
+ // account.
+ // It is expressed in the fiat currency and
+ // is calculated after the cashout fee and the
+ // exchange rate. See the /cashout-rate call.
+ // The client needs to calculate this amount
+ // correctly based on the amount_debit and the cashout rate,
+ // otherwise the request will fail.
+ amount_credit: Amount;
+ }
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The cashout request was correctly created.
+ This returns the `CashoutResponse` response.
+ :http:statuscode:`202 Accepted`:
+ 2FA is required for this operation. This returns the `Challenge` response.
+ :http:statuscode:`404 Not found`:
+ The account pointed by ``$USERNAME`` was not found.
+ :http:statuscode:`409 Conflict`:
+ * ``TALER_EC_BANK_TRANSFER_REQUEST_UID_REUSED``: an operation with the same ``request_uid`` but different details has been submitted before.
+ * ``TALER_EC_BANK_BAD_CONVERSION`` : exchange rate was calculated incorrectly by the client.
+ * ``TALER_EC_BANK_UNALLOWED_DEBIT`` : the account does not have sufficient funds.
+ * ``TALER_EC_BANK_CONFIRM_INCOMPLETE`` : the user did not share any cashout payto to uri where to wire funds.
+ :http:statuscode:`501 Not Implemented`:
+ * ``TALER_EC_BANK_TAN_CHANNEL_NOT_SUPPORTED``: the chosen ``tan_channel`` is not currently supported.
+ * This server does not support conversion, client should check config response.
+
+ **Details:**
+
+ .. ts:def:: CashoutResponse
+
+ interface CashoutResponse {
+ // ID identifying the operation being created
+ cashout_id: Integer;
+ }
+
+.. _circuit-cashout-details:
+
+.. http:get:: /accounts/$USERNAME/cashouts/$CASHOUT_ID
+
+ Returns information about the status of the ``$CASHOUT_ID`` operation.
+ The request is available to the administrator and the account owner.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ Response is a `CashoutStatusResponse`.
+ :http:statuscode:`404 Not found`:
+ The cashout operation was not found.
+ :http:statuscode:`501 Not implemented`:
+ This server does not support conversion, client should check config response.
+
+ **Details:**
+
+ .. ts:def:: CashoutStatusResponse
+
+ interface CashoutStatusResponse {
+ // Amount debited to the regional bank account.
+ amount_debit: Amount;
+
+ // Amount credited to the fiat bank account.
+ amount_credit: Amount;
+
+ // Transaction subject.
+ subject: string;
+
+ // Time when the cashout was created.
+ creation_time: Timestamp;
+ }
+
+.. _circuit-cashouts:
+
+.. http:get:: /accounts/$USERNAME/cashouts
+
+ Returns the list of all cash-out operations for an account.
+
+ **Request:**
+
+ :query delta: *Optional.*
+ Takes value of the form ``N (-N)``, so that at most ``N`` values strictly older (younger) than ``start`` are returned. Defaults to ``-20`` to return the last 20 entries.
+ :query start: *Optional.*
+ Row number threshold, see ``delta`` for its interpretation. Defaults to smallest or biggest row id possible according to ``delta`` sign.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ Response is a `Cashouts`.
+ :http:statuscode:`204 No Content`:
+ No cash-out operations were found.
+ :http:statuscode:`501 Not implemented`:
+ This server does not support conversion, client should check config response.
+
+ **Details:**
+
+ .. ts:def:: Cashouts
+
+ interface Cashouts {
+ // Every string represents a cash-out operation ID.
+ cashouts: CashoutInfo[];
+ }
+
+ .. ts:def:: CashoutInfo
+
+ interface CashoutInfo {
+ cashout_id: Integer;
+ }
+
+.. http:get:: /cashouts
+
+ Returns the list of all cash-out operations for **all** accounts.
+
+ Can only be used by the administrators.
+
+ **Request:**
+
+ :query delta: *Optional.*
+ Takes value of the form ``N (-N)``, so that at most ``N`` values strictly older (younger) than ``start`` are returned. Defaults to ``-20`` to return the last 20 entries.
+ :query start: *Optional.*
+ Row number threshold, see ``delta`` for its interpretation. Defaults to smallest or biggest row id possible according to ``delta`` sign.
+
+ .. note::
+
+ We might want to add a filter in the future to only
+ query pending cashout operations.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ Response is a `GlobalCashouts`.
+ :http:statuscode:`204 No Content`:
+ No cash-out operations were found.
+ :http:statuscode:`501 Not implemented`:
+ This server does not support conversion, client should check config response.
+
+ **Details:**
+
+ .. ts:def:: GlobalCashouts
+
+ interface GlobalCashouts {
+ cashouts: GlobalCashoutInfo[];
+ }
+
+ .. ts:def:: GlobalCashoutInfo
+
+ interface GlobalCashoutInfo {
+ cashout_id: Integer;
+ username: string;
+ }
+
+.. _cashout-rates:
+
+2FA
+---
+
+.. http:post:: /accounts/$USERNAME/challenge/$CHALLENGE_ID
+
+ Send TAN code for the ``CHALLENGE_ID`` challenge.
+
+ This request can be posted several times to trigger TAN retransmission when the current code has expired or too many confirmation attempts have been made.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The TAN code have been sent. This returns `TanTransmission` response.
+ :http:statuscode:`401 Unauthorized`:
+ Invalid credentials or missing rights.
+ :http:statuscode:`404 Not Found`:
+ The challenge was not found.
+ :http:statuscode:`502 Bad Gateway`:
+ * ``TALER_EC_BANK_TAN_CHANNEL_SCRIPT_FAILED``: TAN transmition via ``tan_channel`` failed.
+
+ **Details:**
+
+ .. ts:def:: TanTransmission
+
+ interface TanTransmission {
+ // Channel of the last successful transmission of the TAN challenge.
+ tan_channel: TanChannel;
+
+ // Info of the last successful transmission of the TAN challenge.
+ tan_info: string;
+ }
+
+ .. ts:def:: Challenge
+
+ interface Challenge {
+ // Unique identifier of the challenge to solve to run this protected
+ // operation.
+ challenge_id: string;
+ }
+
+ .. ts:def:: TanChannel
+
+ enum TanChannel {
+ SMS = "sms",
+ EMAIL = "email"
+ }
+
+
+.. http:post:: /accounts/$USERNAME/challenge/$CHALLENGE_ID/confirm
+
+ Solves the ``CHALLENGE_ID`` challenge and allows performing the protected operation.
+
+ When the challenge is confirmed, you can call the protected endpoint again with ``CHALLENGE_ID`` in the ``X-Challenge-Id`` HTTP header and an empty request body.
+
+ **Request:**
+
+ .. ts:def:: ChallengeSolve
+
+ interface ChallengeSolve {
+ // The TAN code that solves $CHALLENGE_ID
+ tan: string;
+ }
+
+ **Response:**
+
+ :http:statuscode:`204 No Content`:
+ The challenge is confirmed.
+ :http:statuscode:`401 Unauthorized`:
+ Invalid credentials or missing rights.
+ :http:statuscode:`404 Not Found`:
+ The challenge was not found.
+ :http:statuscode:`409 Conflict`:
+ * ``TALER_EC_BANK_TAN_CHALLENGE_FAILED`` : wrong TAN.
+ * ``TALER_EC_BANK_TAN_CHALLENGE_EXPIRED`` : expired TAN.
+ :http:statuscode:`429 Too many requests`:
+ Too many failed confirmation attempts, a new TAN must be requested.
+
+
+Monitor
+-------
+
+.. http:get:: /monitor
+
+ When the bank provides conversion between the local currency and an
+ external one, this call lets the bank administrator monitor the cashin
+ and cashout operations that were made from and to the external currency.
+ It shows as well figures related to internal payments made by a Taler
+ exchange component to internal bank accounts. Timeframes are in UTC.
+
+ **Request:**
+
+ :query timeframe: *Optional*.
+ This parameter admits one of the following values. Defaults to 'hour'.
+
+ * hour
+ * day
+ * month
+ * year
+
+ :query date_s: *Optional*.
+ Non-negative date in seconds after the UNIX Epoch. Default to current time.
+ @since v4
+
+ :query which: *Optional*.
+ This parameter points at a particular element of the *timeframe* parameter.
+ Following are the admitted values for each one.
+ Default to the last snapshot taken of the *timeframe* parameter.
+ @deprecated since v4
+
+ * hour: from 00 to 23
+ * day: from 1 to the last day of the current month.
+ * month: from 1 to 12
+ * year: Gregorian year in the YYYY format.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The bank responds with `MonitorResponse`.
+ :http:statuscode:`400 Bad Request`:
+ This error may indicate that the *which* parameter is not appropriate for the selected *timeframe*. For example, timeframe=month and which=20 would result in this error.
+
+ **Details:**
+
+ .. note::
+
+ API consumers may combine the values in the response with other
+ factors to serve different views to their users.
+
+ .. ts:def:: MonitorResponse
+
+ // Union discriminated by the "type" field.
+ type MonitorResponse =
+ | MonitorNoConversion
+ | MonitorWithConversion;
+
+ .. ts:def:: MonitorNoConversion
+
+ // Monitoring stats when conversion is not supported
+ interface MonitorNoConversion {
+ type: "no-conversions";
+
+ // How many payments were made to a Taler exchange by another
+ // bank account.
+ talerInCount: Integer;
+
+ // Overall volume that has been paid to a Taler
+ // exchange by another bank account.
+ talerInVolume: Amount;
+
+ // How many payments were made by a Taler exchange to another
+ // bank account.
+ talerOutCount: Integer;
+
+ // Overall volume that has been paid by a Taler
+ // exchange to another bank account.
+ talerOutVolume: Amount;
+ }
+
+ .. ts:def:: MonitorWithConversion
+
+ // Monitoring stats when conversion is supported
+ interface MonitorWithConversion {
+ type: "with-conversions";
+
+ // How many cashin operations were confirmed by a
+ // wallet owner. Note: wallet owners
+ // are NOT required to be customers of the libeufin-bank.
+ cashinCount: Integer;
+
+ // Overall regional currency that has been paid by the regional admin account
+ // to regional bank accounts to fulfill all the confirmed cashin operations.
+ cashinRegionalVolume: Amount;
+
+ // Overall fiat currency that has been paid to the fiat admin account
+ // by fiat bank accounts to fulfill all the confirmed cashin operations.
+ cashinFiatVolume: Amount;
+
+ // How many cashout operations were confirmed.
+ cashoutCount: Integer;
+
+ // Overall regional currency that has been paid to the regional admin account
+ // by fiat bank accounts to fulfill all the confirmed cashout operations.
+ cashoutRegionalVolume: Amount;
+
+ // Overall fiat currency that has been paid by the fiat admin account
+ // to fiat bank accounts to fulfill all the confirmed cashout operations.
+ cashoutFiatVolume: Amount;
+
+ // How many payments were made to a Taler exchange by another
+ // bank account.
+ talerInCount: Integer;
+
+ // Overall volume that has been paid to a Taler
+ // exchange by another bank account.
+ talerInVolume: Amount;
+
+ // How many payments were made by a Taler exchange to another
+ // bank account.
+ talerOutCount: Integer;
+
+ // Overall volume that has been paid by a Taler
+ // exchange to another bank account.
+ talerOutVolume: Amount;
+ }
+
+
+Endpoints for Integrated Sub-APIs
+---------------------------------
+
+.. http:any:: /taler-integration/*
+
+ All endpoints under this prefix are specified by the.
+ :doc:`GNU Taler bank integration API </core/api-bank-integration>`.
+ This API handles the communication with Taler wallets.
+
+
+.. http:any:: /accounts/$USERNAME/taler-wire-gateway/*
+
+ All endpoints under this prefix are specified
+ by the :doc:`GNU Taler wire gateway API </core/api-bank-wire>`.
+
+ The endpoints are only available for accounts configured with ``is_taler_exchange=true``.
+
+
+.. http:any:: /accounts/$USERNAME/taler-revenue/*
+
+ All endpoints under this prefix are specified
+ by the :doc:`GNU Taler Revenue API </core/api-bank-revenue>`.
+
+
+.. http:any:: /conversion-info/*
+
+ All endpoints under this prefix are specified
+ by the :doc:`GNU Taler Conversion Info API </core/api-bank-conversion-info>`.
+
+
+.. http:post:: /ebicshost
+
+ EBICS base URL. This URL allows clients to make EBICS requests to one of
+ the configured EBICS hosts.
+
+ The Taler bank can be configured to serve bank account transactions and
+ allow payment initiations via the EBICS protocol.
+
+ This is an optional feature, not all implementations of the API support it.
diff --git a/core/api-donau.rst b/core/api-donau.rst
new file mode 100644
index 00000000..09f644ec
--- /dev/null
+++ b/core/api-donau.rst
@@ -0,0 +1,615 @@
+..
+ This file is part of GNU TALER.
+ Copyright (C) 2014-2023 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Christian Grothoff
+ @author Pius Loosli
+ @author Lukas Matyja
+ @author Johannes Casaburi
+
+=====================
+The Donau RESTful API
+=====================
+
+The API specified here follows the :ref:`general conventions <http-common>`
+for all details not specified in the individual requests.
+The `glossary <https://docs.taler.net/glossary.html#glossary>`_
+defines all specific terms used in this section.
+
+.. contents:: Table of Contents
+ :local:
+
+.. _donau-overview:
+
+------------
+API Overview
+------------
+
+This is intended to provide a quick overview of the whole REST API. For a more detailed view of the protocol, see the protocol specification.
+
+The chapters group the families of requests frequently encountered when using the Donau API:
+
+* :ref:`Status information<donau_status>`: get the public signing keys of the Donau, the donation unit key, the Donaus config or some entropy
+* :ref:`Issue receipts<donau_issue>`: For use by charities: Issue receipts for blinded unique donor ids.
+* :ref:`Submit receipts<donau_submit>`: Receive the receipts and, if valid, add all of it's donation units to the donor total. Returns a signature on the total yearly donation amount, hash of taxid+salt and year.
+* :ref:`Charity administration and status information<donau_charity>`:
+
+ * For use by administrators to add/modify a charity
+ * For use by charities to get their remaining donation volume
+
+.. include:: tos.rst
+
+.. _donau_status:
+
+----------------------------------------
+Donau public keys and status information
+----------------------------------------
+
+This API is used by donors and charities to obtain global information about
+the Donau, such as online signing keys and available donation units. This is
+typically the first call any Donau client makes, as it returns information
+required to process all of the other interactions with the Donau. The
+returned information is secured by signature(s) from the Donau, especially the
+long-term offline signing key of the Donau, which clients should cache.
+
+.. http:get:: /keys
+
+ Get a list of all donation units keys offered by the Donau,
+ as well as the Donau's current online signing key (used for donation statements).
+
+ **Request:**
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The Donau responds with a `DonauKeysResponse` object. This request should
+ virtually always be successful. It only fails if the Donau is misconfigured.
+
+ **Details:**
+
+ .. ts:def:: DonauKeysResponse
+
+ interface DonauKeysResponse {
+ // libtool-style representation of the Donau protocol version, see
+ // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
+ // The format is "current:revision:age".
+ version: string;
+
+ // Financial domain this Donau operates for.
+ domain: string;
+
+ // The Donau's base URL.
+ base_url: string;
+
+ // The Donau's currency.
+ currency: string;
+
+ // How many digits should the amounts be rendered
+ // with by default. Small capitals should
+ // be used to render fractions beyond the number
+ // given here (like on gas stations).
+ currency_fraction_digits: Integer;
+
+ // Donation Units offered by this Donau
+ donation_units: DonationUnitKeyGroup[];
+
+ // The Donau's signing keys.
+ signkeys: SignKey[];
+
+ }
+
+ .. ts:def:: DonationUnitKeyGroup
+
+ type DonationUnitKeyGroup =
+ | DonationUnitKeyGroupRsa
+ | DonationUnitKeyGroupCs;
+
+ .. ts:def:: DonationUnitKeyGroupRsa
+
+ interface DonationUnitKeyGroupRsa extends DonationUnitKeyGroupCommon {
+ cipher: "RSA";
+
+ donation_units: ({
+ rsa_pub: RsaPublicKey;
+ } & DonationUnitKeyCommon)[];
+ }
+
+ .. ts:def:: DonationUnitKeyGroupCs
+
+ interface DonationUnitKeyGroupCs extends DonationUnitKeyGroupCommon {
+ cipher: "CS";
+
+ donation_units: ({
+ cs_pub: Cs25519Point;
+ } & DonationUnitKeyCommon)[];
+ }
+
+ .. ts:def:: DonationUnitKeyGroupCommon
+
+ // Common attributes for all donation unit groups
+ interface DonationUnitKeyGroupCommon {
+ // How much was donated based on this donation receipt.
+ value: Amount;
+
+ }
+
+ .. ts:def:: DonationUnitKeyCommon
+
+ interface DonationUnitKeyCommon {
+
+ // For which year is this donation unit key valid.
+ year: Integer;
+
+ // Set to 'true' if the Donau somehow "lost" the private key. The donation unit was not
+ // revoked, but still cannot be used to withdraw receipts at this time (theoretically,
+ // the private key could be recovered in the future; receipts signed with the private key
+ // remain valid).
+ lost?: boolean;
+ }
+
+ .. ts:def:: DonationUnitKey
+
+ type DonationUnitKey =
+ | RsaDonationUnitKey
+ | CSDonationUnitKey;
+
+ .. ts:def:: RsaDonationUnitKey
+
+ interface RsaDonationUnitKey {
+ cipher: "RSA";
+
+ // RSA public key
+ rsa_public_key: RsaPublicKey;
+ }
+
+ .. ts:def:: CSDonationUnitKey
+
+ interface CSDonationUnitKey {
+ cipher: "CS";
+
+ // Public key of the donation unit.
+ cs_public_key: Cs25519Point;
+
+ }
+
+ A signing key in the ``signkeys`` list is a JSON object with the following fields:
+
+ .. ts:def:: SignKey
+
+ interface SignKey {
+ // The actual Donau's EdDSA signing public key.
+ key: EddsaPublicKey;
+
+ // Initial validity date for the signing key.
+ year: Integer;
+
+ }
+
+
+ .. note::
+
+ Both the individual donation units *and* the donation units list is signed,
+ allowing customers to prove that they received an inconsistent list.
+
+.. http:get:: /seed
+
+ Return an entropy seed. The Donau will return a high-entropy
+ value that will differ for every call. The response is NOT in
+ JSON, but simply high-entropy binary data in the HTTP body.
+ This API should be used by wallets to guard themselves against
+ running on low-entropy (bad PRNG) hardware. Naturally, the entropy
+ returned MUST be mixed with locally generated entropy.
+
+.. http:get:: /config
+
+ Return the protocol version, financial domain and currency supported by this
+ Donau backend.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The body is a `DonauVersionResponse`.
+
+ .. ts:def:: DonauVersionResponse
+
+ interface DonauVersionResponse {
+ // libtool-style representation of the Donau protocol version, see
+ // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
+ // The format is "current:revision:age".
+ version: string;
+
+ // Name of the protocol.
+ name: "taler-donau";
+
+ // Currency supported by this Donau.
+ currency: string;
+
+ // Financial domain by this Donau.
+ domain: string;
+
+ }
+
+
+.. _donau_issue:
+
+--------------
+Issue receipts
+--------------
+
+Inspired by the Taler exchange :ref:`Withdrawal<exchange-withdrawal>`.
+
+This API is used by the charity to obtain valid, attested donation receipts from the Donau.
+Use the :ref:`charity GET route<donau_charity_get>` to see the remaining donation volume for the current year.
+
+
+All incoming `BDID` are recorded under the corresponding charity_id by the Donau.
+
+.. http:POST:: /batch-issue/$CHARITY_ID
+
+ Send in a `IssueReceiptsRequest` and ask the Donau to sign all it's contained `BDID`.
+
+ **Request:** `IssueReceiptsRequest`
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The request was successful, and the response is a `BSDonationReceipts`.
+ :http:statuscode:`403 Forbidden`:
+ The charity signature is invalid. This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ At least one of the donation unit keys is not known to the Donau. Comes with a `DonationUnitUnknownError`. This suggests a bug in the donor as it should have used current donation unit keys from :ref:`/keys<donau_status>`.
+ :http:statuscode:`409 Conflict`:
+ The donation volume of the charity is not sufficient to issue donation receipts vor all sent in blinded udids. The response is a `IssueError` object.
+ :http:statuscode:`410 Gone`:
+ The requested donation unit key is not yet or no longer valid. It either before the validity start, past the expiration or was revoked. The response is a `DonationUnitExpiredMessage`. Clients must evaluate the error code provided to understand which of the cases this is and handle it accordingly.
+
+ **Details:**
+
+ .. ts:def:: IssueReceiptsRequest
+
+ interface IssueReceiptsRequest {
+ charity_signature: EddsaSignature;
+ year: Integer;
+ bdids: BDID[];
+ }
+
+ .. ts:def:: BDID
+
+ interface BDID {
+ donau_pub_hash: HashCode;
+ taxpayer_blinded_id: BDIDEnvelope;
+ }
+
+ .. ts:def:: BDIDEnvelope
+
+ type BDIDEnvelope = RSABDIDEnvelope | CSBDIDEnvelope ;
+
+ .. ts:def:: RSABDIDEnvelope
+
+ interface RSABDIDEnvelope {
+ cipher: "RSA" | "RSA+age_restricted";
+ rsa_blinded_UDID: string; // Crockford Base32 encoded
+ }
+
+ .. ts:def:: CSBDIDEnvelope
+
+ // For donation unit signatures based on Blind Clause-Schnorr, the UDID
+ // consists of the public nonce and two Curve25519 scalars which are two
+ // blinded challenges in the Blinded Clause-Schnorr signature scheme.
+ // See https://taler.net/papers/cs-thesis.pdf for details.
+ interface CSBDIDEnvelope {
+ cipher: "CS" | "CS+age_restricted";
+ cs_nonce: string; // Crockford Base32 encoded
+ cs_blinded_c0: string; // Crockford Base32 encoded
+ cs_blinded_c1: string; // Crockford Base32 encoded
+ }
+
+ .. ts:def:: BDIDBlindingKeyP
+
+ // Secret for blinding/unblinding.
+ // An RSA blinding secret, which is basically
+ // a 256-bit nonce, converted to Crockford Base32.
+ type BDIDBlindingKeyP = string;
+
+ .. ts:def:: BSDonationReceipts
+
+ interface DonationReceipts {
+ blind_signed_receipt_signatures: DonationReceiptSignature[];
+ }
+
+ .. ts:def:: DonationReceiptSignature
+
+ .. ts:def:: BlindedDonationReceiptSignature
+
+ type BlindedDonationReceiptSignature =
+ | RSABlindedDonationReceiptSignature
+ | CSBlindedDonationReceiptSignature;
+
+ .. ts:def:: RSABlindedDonationReceiptSignature
+
+ interface RSABlindedDonationReceiptSignature {
+ cipher: "RSA";
+
+ // (blinded) RSA signature
+ blinded_rsa_signature: BlindedRsaSignature;
+ }
+
+ .. ts:def:: CSBlindedDonationReceiptSignature
+
+ interface CSBlindedDonationReceiptSignature {
+ type: "CS";
+
+ // Signer chosen bit value, 0 or 1, used
+ // in Clause Blind Schnorr to make the
+ // ROS problem harder.
+ b: Integer;
+
+ // Blinded scalar calculated from c_b.
+ s: Cs25519Scalar;
+ }
+
+
+ type DonationReceiptSignature = RSADonationReceiptSignature | CSDonationReceiptSignature ;
+
+ .. ts:def:: RSADonationReceiptSignature
+
+ interface RSADonationReceiptSignature {
+ cipher: "RSA";
+ rsa_blinded_donation_receipt_sig: string; // Crockford Base32 encoded
+ }
+
+ .. ts:def:: CSDonationReceiptSignature
+
+ interface CSDonationReceiptSignature {
+ cipher: "CS";
+ cs_nonce: string; // Crockford Base32 encoded
+ cs_blinded_c0: string; // Crockford Base32 encoded
+ cs_blinded_c1: string; // Crockford Base32 encoded
+ }
+
+ .. ts:def:: IssueError
+
+ interface IssueError{
+ max_per_year: Amount;
+ current_year: Amount;
+ }
+
+ .. ts:def:: DonationUnitUnknownError
+
+ interface DonationUnitUnknownError{
+ unknown_hash_pub_donation_unit: HashCode[];
+ donau_pub: EddsaPublicKey;
+ donau_sig: EddsaSignature;
+ }
+
+ .. ts:def:: DonationUnitExpiredMessage
+
+ interface DonationUnitExpiredMessage{
+ h_donation_unit_pub: HashCode;
+ donau_pub: EddsaPublicKey;
+ donau_sig: EddsaSignature;
+ }
+
+.. _donau_submit:
+
+---------------
+Submit receipts
+---------------
+
+Inspired by the Taler exchange :ref:`Deposit<deposit-par>`.
+
+.. http:POST:: /submit
+
+ Send in donation receipts for the past fiscal year, receive signed total back.
+
+ **Request:** `SubmitDonationReceiptsRequest`
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The request was successful, and the response is a `SubmitResponse`.
+ :http:statuscode:`403 Forbidden`:
+ One of the signatures is invalid. This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ At least one of the donation unit keys is not known to the Donau. Comes with a `DonationUnitUnknownError`.
+ :http:statuscode:`410 Gone`:
+ The requested donation unit key is not yet or no longer valid. It either before the validity start, past the expiration or was revoked. The response is a `DonationUnitExpiredMessage`. Clients must evaluate the error code provided to understand which of the cases this is and handle it accordingly. FIXME: text does not match our use case well.
+
+ **Details:**
+
+ .. ts:def:: SubmitDonationReceiptsRequest
+
+ interface SubmitDonationReceiptsRequest{
+ // hashed taxpayer ID plus salt
+ taxnr_hashed: HashCode;
+ // All donation receipts must be for this year.
+ year: Integer;
+ // Receipts should be sorted by amount.
+ donation_receipts: DonationReceipt[];
+ }
+
+ .. ts:def:: DonationReceipt
+
+ interface DonationReceipt{
+ donation_unit_pub_hash: HashCode;
+ nonce: string;
+ donau_sig: DonationSignature
+ }
+
+ .. ts:def:: DonationSignature
+
+ type DonationSignature =
+ RsaDonationSignature | CSDonationSignature;
+
+ .. ts:def:: RsaDonationSignature
+
+ interface RsaDonationSignature {
+ cipher: "RSA";
+
+ // RSA signature
+ rsa_signature: RsaSignature;
+ }
+
+ .. ts:def:: CSDonationSignature
+
+ interface CSDonationSignature {
+ type: "CS";
+
+ // R value component of the signature.
+ cs_signature_r: Cs25519Point;
+
+ // s value component of the signature.
+ cs_signature_s: Cs25519Scalar:
+ }
+
+
+
+ .. ts:def:: SubmitResponse
+
+ interface SubmitResponse{
+ // *accepted* total
+ total: Amount;
+ // signature over taxid_hashed, total, year
+ signature: EddsaSignature;
+ }
+
+.. _donau_charity:
+
+---------------------------------------------
+Charity administration and status information
+---------------------------------------------
+
+The administration requests require an authorized bearer token to be set in the HTTP "Authorization" Header. This token can be set by a proxy validating authentication/authorization (using e.g. LDAP).
+The GET status requests require an authorized bearer token as well.
+
+.. http:GET:: /charities
+
+ GET all charities. Only allowed if the request comes with the administration bearer token.
+
+ return all charities
+
+ **Request:**
+
+ **Reponse:**
+
+ :http:statuscode:`200 OK`:
+ The request was successful, and the response is a `Charities`.
+
+ **Details:**
+
+ .. ts:def:: Charities
+
+ interface Charities{
+ charities: CharitySummary[];
+ }
+
+ .. ts:def:: CharitySummary
+
+ interface CharitySummary{
+ charity_id: Integer;
+ name: string;
+ max_per_year: Amount;
+ receipts_to_date: Amount;
+ }
+
+.. _donau_charity_get:
+
+.. http:get:: /charities/$CHARITY_ID
+
+ GET a specific charity. Only allowed if the request comes with the charity or administration bearer token.
+
+ Request information about a charity.
+
+ **Request:**
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The Donau responds with a `Charity` object
+ :http:statuscode:`404 Not found`:
+ The charity id does not belong to a charity known to the Donau.
+
+ .. ts:def:: Charity
+
+ interface Charity {
+ charity_pub: EddsaPublicKey;
+ name: string;
+ url: string;
+ max_per_year: Amount;
+ receipts_to_date: Amount;
+ current_year: Integer;
+ }
+
+.. http:POST:: /charity
+
+ Add a charity. Only allowed if the request comes with the administrator bearer token.
+
+ **Request:** `CharityRequest`
+
+ **Response:**
+
+ **Details:**
+
+ :http:statuscode:`201 Created`:
+ The request was successful, and the response is a `CharityResponse`.
+
+ :http:statuscode:`403 Forbidden`:
+ The request did not contain an accepted administrator bearer token in it's header.
+
+ .. ts:def:: CharityRequest
+
+ interface CharityRequest{
+ charity_pub: EddsaPublicKey;
+ name: string;
+ url: string;
+ max_per_year: Amount;
+ receipts_to_date: Amount;
+ current_year: Integer;
+ }
+
+ .. ts:def:: CharityResponse
+
+ interface CharityResponse{
+ id: Integer;
+ }
+
+
+.. http:PATCH:: /charities/{id}
+
+ Modify a charity. Only allowed if the request comes with the administrator bearer token.
+
+ **Request:** `CharityRequest`
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The request was successful.
+
+ :http:statuscode:`403 Forbidden`:
+ The request did not contain an accepted administrator bearer token in it's header.
+
+
+.. http:DELETE:: /charities/{id}
+
+ Delete (or deactivate) a charity. Only allowed if the request comes with the administrator bearer token.
+
+ **Request:**
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The request was successful.
+
+ :http:statuscode:`403 Forbidden`:
+ The request did not contain an accepted administrator bearer token in it's header.
diff --git a/core/api-error.rst b/core/api-error.rst
deleted file mode 100644
index fcd7374b..00000000
--- a/core/api-error.rst
+++ /dev/null
@@ -1,1205 +0,0 @@
-..
- This file is part of GNU TALER.
- Copyright (C) 2014, 2015, 2016 GNUnet e.V. and INRIA
- TALER 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.
- 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 Affero General Public License for more details.
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-
- @author Marcello Stanisci
-
-..
- The reason to have a dedicated page for error codes was due to a buggy
- behaviour in pages cross-linking: was not possible from other pages to
- reference the '_error-codes' label (see just below) if we kept in api-common.rst
- (which is the best place to place this error codes list).
-
------------
-Error Codes
------------
-
-The following list shows error codes defined in
-`<EXCHANGE-REPO>/src/include/taler_error_codes.h <https://git.taler.net/exchange.git/tree/src/include/taler_error_codes.h>`_.
-
-.. _error-codes:
-.. _TALER_ErrorCode:
-.. code-block:: c
-
- /**
- * Enumeration with all possible Taler error codes.
- */
- enum TALER_ErrorCode {
-
- /**
- * Special code to indicate no error (or no "code" present).
- */
- TALER_EC_NONE = 0,
-
- /**
- * Special code to indicate that a non-integer error code was
- * returned in the JSON response.
- */
- TALER_EC_INVALID = 1,
-
- /**
- * The response we got from the server was not even in JSON format.
- */
- TALER_EC_INVALID_RESPONSE = 2,
-
- /**
- * Generic implementation error: this function was not yet implemented.
- */
- TALER_EC_NOT_IMPLEMENTED = 3,
-
- /* ********** generic error codes ************* */
-
- /**
- * The exchange failed to even just initialize its connection to the
- * database.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_DB_SETUP_FAILED = 1001,
-
- /**
- * The exchange encountered an error event to just start
- * the database transaction.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_DB_START_FAILED = 1002,
-
- /**
- * The exchange encountered an error event to commit
- * the database transaction (hard, unrecoverable error).
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_DB_COMMIT_FAILED_HARD = 1003,
-
- /**
- * The exchange encountered an error event to commit
- * the database transaction, even after repeatedly
- * retrying it there was always a conflicting transaction.
- * (This indicates a repeated serialization error; should
- * only happen if some client maliciously tries to create
- * conflicting concurrent transactions.)
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_DB_COMMIT_FAILED_ON_RETRY = 1004,
-
- /**
- * The exchange had insufficient memory to parse the request. This
- * response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_PARSER_OUT_OF_MEMORY = 1005,
-
- /**
- * The JSON in the client's request to the exchange was malformed.
- * (Generic parse error).
- * This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_JSON_INVALID = 1006,
-
- /**
- * The JSON in the client's request to the exchange was malformed.
- * Details about the location of the parse error are provided.
- * This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_JSON_INVALID_WITH_DETAILS = 1007,
-
- /**
- * A required parameter in the request to the exchange was missing.
- * This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_PARAMETER_MISSING = 1008,
-
- /**
- * A parameter in the request to the exchange was malformed.
- * This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_PARAMETER_MALFORMED = 1009,
-
- /* ********** request-specific error codes ************* */
-
- /**
- * The given reserve does not have sufficient funds to admit the
- * requested withdraw operation at this time. The response includes
- * the current "balance" of the reserve as well as the transaction
- * "history" that led to this balance. This response is provided
- * with HTTP status code MHD_HTTP_FORBIDDEN.
- */
- TALER_EC_WITHDRAW_INSUFFICIENT_FUNDS = 1100,
-
- /**
- * The exchange has no information about the "reserve_pub" that
- * was given.
- * This response is provided with HTTP status code MHD_HTTP_NOT_FOUND.
- */
- TALER_EC_WITHDRAW_RESERVE_UNKNOWN = 1101,
-
- /**
- * The amount to withdraw together with the fee exceeds the
- * numeric range for Taler amounts. This is not a client
- * failure, as the coin value and fees come from the exchange's
- * configuration.
- * This response is provided with HTTP status code MHD_HTTP_INTERNAL_ERROR.
- */
- TALER_EC_WITHDRAW_AMOUNT_FEE_OVERFLOW = 1102,
-
- /**
- * All of the deposited amounts into this reserve total up to a
- * value that is too big for the numeric range for Taler amounts.
- * This is not a client failure, as the transaction history comes
- * from the exchange's configuration. This response is provided
- * with HTTP status code MHD_HTTP_INTERNAL_ERROR.
- */
- TALER_EC_WITHDRAW_AMOUNT_DEPOSITS_OVERFLOW = 1103,
-
- /**
- * For one of the historic withdrawals from this reserve, the
- * exchange could not find the denomination key.
- * This is not a client failure, as the transaction history comes
- * from the exchange's configuration. This response is provided
- * with HTTP status code MHD_HTTP_INTERNAL_ERROR.
- */
- TALER_EC_WITHDRAW_HISTORIC_DENOMINATION_KEY_NOT_FOUND = 1104,
-
- /**
- * All of the withdrawals from reserve total up to a
- * value that is too big for the numeric range for Taler amounts.
- * This is not a client failure, as the transaction history comes
- * from the exchange's configuration. This response is provided
- * with HTTP status code MHD_HTTP_INTERNAL_ERROR.
- */
- TALER_EC_WITHDRAW_AMOUNT_WITHDRAWALS_OVERFLOW = 1105,
-
- /**
- * The exchange somehow knows about this reserve, but there seems to
- * have been no wire transfers made. This is not a client failure,
- * as this is a database consistency issue of the exchange. This
- * response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_ERROR.
- */
- TALER_EC_WITHDRAW_RESERVE_WITHOUT_WIRE_TRANSFER = 1106,
-
- /**
- * The exchange failed to create the signature using the
- * denomination key. This response is provided with HTTP status
- * code MHD_HTTP_INTERNAL_ERROR.
- */
- TALER_EC_WITHDRAW_SIGNATURE_FAILED = 1107,
-
- /**
- * The exchange failed to store the withdraw operation in its
- * database. This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_ERROR.
- */
- TALER_EC_WITHDRAW_DB_STORE_ERROR = 1108,
-
- /**
- * The exchange failed to check against historic withdraw data from
- * the database (as part of ensuring the idempotency of the operation).
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_ERROR.
- */
- TALER_EC_WITHDRAW_DB_FETCH_ERROR = 1109,
-
- /**
- * The exchange is not aware of the denomination key
- * the wallet requested for the withdrawal.
- * This response is provided
- * with HTTP status code MHD_HTTP_NOT_FOUND.
- */
- TALER_EC_WITHDRAW_DENOMINATION_KEY_NOT_FOUND = 1110,
-
- /**
- * The signature of the reserve is not valid. This response is
- * provided with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_WITHDRAW_RESERVE_SIGNATURE_INVALID = 1111,
-
- /**
- * The exchange failed to obtain the transaction history of the
- * given reserve from the database while generating an insufficient
- * funds error.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_WITHDRAW_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS = 1112,
-
- /**
- * When computing the reserve history, we ended up with a negative
- * overall balance, which should be impossible.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_WITHDRAW_RESERVE_HISTORY_IMPOSSIBLE = 1113,
-
- /**
- * The exchange failed to obtain the transaction history of the
- * given reserve from the database.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_RESERVE_STATUS_DB_ERROR = 1150,
-
-
- /**
- * The respective coin did not have sufficient residual value
- * for the /deposit operation (i.e. due to double spending).
- * The "history" in the response provides the transaction history
- * of the coin proving this fact. This response is provided
- * with HTTP status code MHD_HTTP_FORBIDDEN.
- */
- TALER_EC_DEPOSIT_INSUFFICIENT_FUNDS = 1200,
-
- /**
- * The exchange failed to obtain the transaction history of the
- * given coin from the database (this does not happen merely because
- * the coin is seen by the exchange for the first time).
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_DEPOSIT_HISTORY_DB_ERROR = 1201,
-
- /**
- * The exchange failed to store the /depost information in the
- * database. This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_DEPOSIT_STORE_DB_ERROR = 1202,
-
- /**
- * The exchange database is unaware of the denomination key that
- * signed the coin (however, the exchange process is; this is not
- * supposed to happen; it can happen if someone decides to purge the
- * DB behind the back of the exchange process). Hence the deposit
- * is being refused. This response is provided with HTTP status
- * code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_DEPOSIT_DB_DENOMINATION_KEY_UNKNOWN = 1203,
-
- /**
- * The exchange database is unaware of the denomination key that
- * signed the coin (however, the exchange process is; this is not
- * supposed to happen; it can happen if someone decides to purge the
- * DB behind the back of the exchange process). Hence the deposit
- * is being refused. This response is provided with HTTP status
- * code MHD_HTTP_NOT_FOUND.
- */
- TALER_EC_DEPOSIT_DENOMINATION_KEY_UNKNOWN = 1204,
-
- /**
- * The signature of the coin is not valid. This response is
- * provided with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_DEPOSIT_COIN_SIGNATURE_INVALID = 1205,
-
- /**
- * The signature of the denomination key over the coin is not valid.
- * This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_DEPOSIT_DENOMINATION_SIGNATURE_INVALID = 1206,
-
- /**
- * The stated value of the coin after the deposit fee is subtracted
- * would be negative.
- * This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_DEPOSIT_NEGATIVE_VALUE_AFTER_FEE = 1207,
-
- /**
- * The stated refund deadline is after the wire deadline.
- * This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE = 1208,
-
- /**
- * The exchange does not recognize the validity of or support the
- * given wire format type.
- * This response is provided
- * with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE = 1209,
-
- /**
- * The exchange failed to canonicalize and hash the given wire format.
- * This response is provided
- * with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_JSON = 1210,
-
- /**
- * The hash of the given wire address does not match the hash
- * specified in the contract.
- * This response is provided
- * with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_CONTRACT_HASH_CONFLICT = 1211,
-
- /**
- * The exchange failed to obtain the transaction history of the
- * given coin from the database while generating an insufficient
- * funds error.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_DEPOSIT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS = 1212,
-
- /**
- * The exchange detected that the given account number
- * is invalid for the selected wire format type.
- * This response is provided
- * with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_ACCOUNT_NUMBER = 1213,
-
- /**
- * The signature over the given wire details is invalid.
- * This response is provided
- * with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_SIGNATURE = 1214,
-
- /**
- * The bank specified in the wire transfer format is not supported
- * by this exchange.
- * This response is provided
- * with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_BANK = 1215,
-
- /**
- * No wire format type was specified in the JSON wire format
- * details.
- * This response is provided
- * with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE_MISSING = 1216,
-
- /**
- * The given wire format type is not supported by this
- * exchange.
- * This response is provided
- * with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE_UNSUPPORTED = 1217,
-
-
- /**
- * The respective coin did not have sufficient residual value
- * for the /refresh/melt operation. The "history" in this
- * response provdes the "residual_value" of the coin, which may
- * be less than its "original_value". This response is provided
- * with HTTP status code MHD_HTTP_FORBIDDEN.
- */
- TALER_EC_MELT_INSUFFICIENT_FUNDS = 1300,
-
- /**
- * The exchange is unaware of the denomination key that was
- * used to sign the melted coin. This response is provided
- * with HTTP status code MHD_HTTP_NOT_FOUND.
- */
- TALER_EC_MELT_DENOMINATION_KEY_NOT_FOUND = 1301,
-
- /**
- * The exchange had an internal error reconstructing the
- * transaction history of the coin that was being melted.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_MELT_COIN_HISTORY_COMPUTATION_FAILED = 1302,
-
- /**
- * The exchange failed to check against historic melt data from the
- * database (as part of ensuring the idempotency of the operation).
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_ERROR.
- */
- TALER_EC_MELT_DB_FETCH_ERROR = 1303,
-
- /**
- * The exchange failed to store session data in the
- * database.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_ERROR.
- */
- TALER_EC_MELT_DB_STORE_SESSION_ERROR = 1304,
-
- /**
- * The exchange failed to store refresh order data in the
- * database.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_ERROR.
- */
- TALER_EC_MELT_DB_STORE_ORDER_ERROR = 1305,
-
- /**
- * The exchange failed to store commit data in the
- * database.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_ERROR.
- */
- TALER_EC_MELT_DB_STORE_COMMIT_ERROR = 1306,
-
- /**
- * The exchange failed to store transfer keys in the
- * database.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_ERROR.
- */
- TALER_EC_MELT_DB_STORE_TRANSFER_ERROR = 1307,
-
- /**
- * The exchange is unaware of the denomination key that was
- * requested for one of the fresh coins. This response is provided
- * with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_MELT_FRESH_DENOMINATION_KEY_NOT_FOUND = 1308,
-
- /**
- * The exchange encountered a numeric overflow totaling up
- * the cost for the refresh operation. This response is provided
- * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_MELT_COST_CALCULATION_OVERFLOW = 1309,
-
- /**
- * During the transaction phase, the exchange could suddenly
- * no longer find the denomination key that was
- * used to sign the melted coin. This response is provided
- * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_MELT_DB_DENOMINATION_KEY_NOT_FOUND = 1310,
-
- /**
- * The exchange encountered melt fees exceeding the melted
- * coin's contribution. This response is provided
- * with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_MELT_FEES_EXCEED_CONTRIBUTION = 1311,
-
- /**
- * The exchange's cost calculation does not add up to the
- * melt fees specified in the request. This response is provided
- * with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_MELT_FEES_MISSMATCH = 1312,
-
- /**
- * The denomination key signature on the melted coin is invalid.
- * This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_MELT_DENOMINATION_SIGNATURE_INVALID = 1313,
-
- /**
- * The exchange's cost calculation shows that the melt amount
- * is below the costs of the transaction. This response is provided
- * with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_MELT_AMOUNT_INSUFFICIENT = 1314,
-
- /**
- * The signature made with the coin to be melted is invalid.
- * This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_MELT_COIN_SIGNATURE_INVALID = 1315,
-
- /**
- * The size of the cut-and-choose dimension of the
- * blinded coins request does not match #TALER_CNC_KAPPA.
- * This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_MELT_CNC_COIN_ARRAY_SIZE_INVALID = 1316,
-
- /**
- * The size of the cut-and-choose dimension of the
- * transfer keys request does not match #TALER_CNC_KAPPA.
- * This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_MELT_CNC_TRANSFER_ARRAY_SIZE_INVALID = 1317,
-
- /**
- * The exchange failed to obtain the transaction history of the
- * given coin from the database while generating an insufficient
- * funds error.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_MELT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS = 1318,
-
- /**
- * The provided transfer keys do not match up with the
- * original commitment. Information about the original
- * commitment is included in the response. This response is
- * provided with HTTP status code MHD_HTTP_CONFLICT.
- */
- TALER_EC_REVEAL_COMMITMENT_VIOLATION = 1350,
-
- /**
- * Failed to blind the envelope to reconstruct the blinded
- * coins for revelation checks.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_ERROR.
- */
- TALER_EC_REVEAL_BLINDING_ERROR = 1351,
-
- /**
- * Failed to produce the blinded signatures over the coins
- * to be returned.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_ERROR.
- */
- TALER_EC_REVEAL_SIGNING_ERROR = 1352,
-
- /**
- * The exchange is unaware of the refresh session specified in
- * the request.
- * This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_REVEAL_SESSION_UNKNOWN = 1353,
-
- /**
- * The exchange failed to retrieve valid session data from the
- * database.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_ERROR.
- */
- TALER_EC_REVEAL_DB_FETCH_SESSION_ERROR = 1354,
-
- /**
- * The exchange failed to retrieve order data from the
- * database.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_ERROR.
- */
- TALER_EC_REVEAL_DB_FETCH_ORDER_ERROR = 1355,
-
- /**
- * The exchange failed to retrieve transfer keys from the
- * database.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_ERROR.
- */
- TALER_EC_REVEAL_DB_FETCH_TRANSFER_ERROR = 1356,
-
- /**
- * The exchange failed to retrieve commitment data from the
- * database.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_ERROR.
- */
- TALER_EC_REVEAL_DB_FETCH_COMMIT_ERROR = 1357,
-
- /**
- * The size of the cut-and-choose dimension of the
- * private transfer keys request does not match #TALER_CNC_KAPPA - 1.
- * This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_REVEAL_CNC_TRANSFER_ARRAY_SIZE_INVALID = 1358,
-
-
- /**
- * The coin specified in the link request is unknown to the exchange.
- * This response is provided with HTTP status code
- * MHD_HTTP_NOT_FOUND.
- */
- TALER_EC_LINK_COIN_UNKNOWN = 1400,
-
-
- /**
- * The exchange knows literally nothing about the coin we were asked
- * to refund. But without a transaction history, we cannot issue a
- * refund. This is kind-of OK, the owner should just refresh it
- * directly without executing the refund. This response is provided
- * with HTTP status code MHD_HTTP_NOT_FOUND.
- */
- TALER_EC_REFUND_COIN_NOT_FOUND = 1500,
-
- /**
- * We could not process the refund request as the coin's transaction
- * history does not permit the requested refund at this time. The
- * "history" in the response proves this. This response is provided
- * with HTTP status code MHD_HTTP_CONFLICT.
- */
- TALER_EC_REFUND_CONFLICT = 1501,
-
- /**
- * The exchange knows about the coin we were asked to refund, but
- * not about the specific /deposit operation. Hence, we cannot
- * issue a refund (as we do not know if this merchant public key is
- * authorized to do a refund). This response is provided with HTTP
- * status code MHD_HTTP_NOT_FOUND.
- */
- TALER_EC_REFUND_DEPOSIT_NOT_FOUND = 1503,
-
- /**
- * The currency specified for the refund is different from
- * the currency of the coin. This response is provided with HTTP
- * status code MHD_HTTP_PRECONDITION_FAILED.
- */
- TALER_EC_REFUND_CURRENCY_MISSMATCH = 1504,
-
- /**
- * When we tried to check if we already paid out the coin, the
- * exchange's database suddenly disagreed with data it previously
- * provided (internal inconsistency).
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_REFUND_DB_INCONSISTENT = 1505,
-
- /**
- * The exchange can no longer refund the customer/coin as the
- * money was already transferred (paid out) to the merchant.
- * (It should be past the refund deadline.)
- * This response is provided with HTTP status code
- * MHD_HTTP_GONE.
- */
- TALER_EC_REFUND_MERCHANT_ALREADY_PAID = 1506,
-
- /**
- * The amount the exchange was asked to refund exceeds
- * (with fees) the total amount of the deposit (including fees).
- * This response is provided with HTTP status code
- * MHD_HTTP_PRECONDITION_FAILED.
- */
- TALER_EC_REFUND_INSUFFICIENT_FUNDS = 1507,
-
- /**
- * The exchange failed to recover information about the
- * denomination key of the refunded coin (even though it
- * recognizes the key). Hence it could not check the fee
- * structure.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_REFUND_DENOMINATION_KEY_NOT_FOUND = 1508,
-
- /**
- * The refund fee specified for the request is lower than
- * the refund fee charged by the exchange for the given
- * denomination key of the refunded coin.
- * This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_REFUND_FEE_TOO_LOW = 1509,
-
- /**
- * The exchange failed to store the refund information to
- * its database.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_REFUND_STORE_DB_ERROR = 1510,
-
- /**
- * The refund fee is specified in a different currency
- * than the refund amount.
- * This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_REFUND_FEE_CURRENCY_MISSMATCH = 1511,
-
- /**
- * The refunded amount is smaller than the refund fee,
- * which would result in a negative refund.
- * This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_REFUND_FEE_ABOVE_AMOUNT = 1512,
-
- /**
- * The signature of the merchant is invalid.
- * This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_REFUND_MERCHANT_SIGNATURE_INVALID = 1513,
-
-
- /**
- * The wire format specified in the "sender_account_details"
- * is not understood or not supported by this exchange.
- * Returned with an HTTP status code of MHD_HTTP_NOT_FOUND.
- * (As we did not find an interpretation of the wire format.)
- */
- TALER_EC_ADMIN_ADD_INCOMING_WIREFORMAT_UNSUPPORTED = 1600,
-
- /**
- * The currency specified in the "amount" parameter is not
- * supported by this exhange. Returned with an HTTP status
- * code of MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_ADMIN_ADD_INCOMING_CURRENCY_UNSUPPORTED = 1601,
-
- /**
- * The exchange failed to store information about the incoming
- * transfer in its database. This response is provided with HTTP
- * status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_ADMIN_ADD_INCOMING_DB_STORE = 1602,
-
- /**
- * The exchange encountered an error (that is not about not finding
- * the wire transfer) trying to look up a wire transfer identifier
- * in the database. This response is provided with HTTP
- * status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_TRANSFERS_GET_DB_FETCH_FAILED = 1700,
-
- /**
- * The exchange found internally inconsistent data when resolving a
- * wire transfer identifier in the database. This response is
- * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_TRANSFERS_GET_DB_INCONSISTENT = 1701,
-
- /**
- * The exchange did not find information about the specified
- * wire transfer identifier in the database. This response is
- * provided with HTTP status code MHD_HTTP_NOT_FOUND.
- */
- TALER_EC_TRANSFERS_GET_WTID_NOT_FOUND = 1702,
-
-
- /**
- * The exchange found internally inconsistent fee data when
- * resolving a transaction in the database. This
- * response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_DEPOSITS_GET_DB_FEE_INCONSISTENT = 1800,
-
- /**
- * The exchange encountered an error (that is not about not finding
- * the transaction) trying to look up a transaction
- * in the database. This response is provided with HTTP
- * status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_DEPOSITS_GET_DB_FETCH_FAILED = 1801,
-
- /**
- * The exchange did not find information about the specified
- * transaction in the database. This response is
- * provided with HTTP status code MHD_HTTP_NOT_FOUND.
- */
- TALER_EC_DEPOSITS_GET_NOT_FOUND = 1802,
-
- /**
- * The exchange failed to identify the wire transfer of the
- * transaction (or information about the plan that it was supposed
- * to still happen in the future). This response is provided with
- * HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_DEPOSITS_GET_WTID_RESOLUTION_ERROR = 1803,
-
- /**
- * The signature of the merchant is invalid.
- * This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_DEPOSITS_GET_MERCHANT_SIGNATURE_INVALID = 1804,
-
-
- /* *********** Merchant backend error codes ********* */
-
- /**
- * The backend could not find the merchant instance specified
- * in the request. This response is
- * provided with HTTP status code MHD_HTTP_NOT_FOUND.
- */
- TALER_EC_CONTRACT_INSTANCE_UNKNOWN = 2000,
-
- /**
- * The exchange failed to provide a meaningful response
- * to a /deposit request. This response is provided
- * with HTTP status code MHD_HTTP_SERVICE_UNAVAILABLE.
- */
- TALER_EC_PAY_EXCHANGE_FAILED = 2101,
-
- /**
- * The merchant failed to commit the exchange's response to
- * a /deposit request to its database. This response is provided
- * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_PAY_DB_STORE_PAY_ERROR = 2102,
-
- /**
- * The specified exchange is not supported/trusted by
- * this merchant. This response is provided
- * with HTTP status code MHD_HTTP_PRECONDITION_FAILED.
- */
- TALER_EC_PAY_EXCHANGE_REJECTED = 2103,
-
- /**
- * The denomination key used for payment is not listed among the
- * denomination keys of the exchange. This response is provided
- * with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_PAY_DENOMINATION_KEY_NOT_FOUND = 2104,
-
- /**
- * The denomination key used for payment is not audited by an
- * auditor approved by the merchant. This response is provided
- * with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_PAY_DENOMINATION_KEY_AUDITOR_FAILURE = 2105,
-
- /**
- * There was an integer overflow totaling up the amounts or
- * deposit fees in the payment. This response is provided
- * with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_PAY_AMOUNT_OVERFLOW = 2106,
-
- /**
- * The deposit fees exceed the total value of the payment.
- * This response is provided
- * with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_PAY_FEES_EXCEED_PAYMENT = 2107,
-
- /**
- * After considering deposit fees, the payment is insufficient
- * to satisfy the required amount for the contract.
- * This response is provided
- * with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_PAY_PAYMENT_INSUFFICIENT_DUE_TO_FEES = 2108,
-
- /**
- * While the merchant is happy to cover all applicable deposit fees,
- * the payment is insufficient to satisfy the required amount for
- * the contract. This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_PAY_PAYMENT_INSUFFICIENT = 2109,
-
- /**
- * The signature over the contract of one of the coins
- * was invalid. This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_PAY_COIN_SIGNATURE_INVALID = 2110,
-
- /**
- * We failed to contact the exchange for the /pay request.
- * This response is provided
- * with HTTP status code MHD_HTTP_SERVICE_UNAVAILABLE.
- */
- TALER_EC_PAY_EXCHANGE_TIMEOUT = 2111,
-
- /**
- * The backend could not find the merchant instance specified
- * in the request. This response is
- * provided with HTTP status code MHD_HTTP_NOT_FOUND.
- */
- TALER_EC_PAY_INSTANCE_UNKNOWN = 2112,
-
- /**
- * The signature over the contract of the merchant
- * was invalid. This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_PAY_MERCHANT_SIGNATURE_INVALID = 2113,
-
- /**
- * The refund deadline was after the transfer deadline.
- * This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_PAY_REFUND_DEADLINE_PAST_WIRE_TRANSFER_DEADLINE = 2114,
-
- /**
- * The request fails to provide coins for the payment.
- * This response is provided with HTTP status code
- * MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_PAY_COINS_ARRAY_EMPTY = 2115,
-
- /**
- * The merchant failed to fetch the merchant's previous state with
- * respect to a /pay request from its database. This response is
- * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_PAY_DB_FETCH_PAY_ERROR = 2116,
-
- /**
- * The merchant failed to fetch the merchant's previous state with
- * respect to transactions from its database. This response is
- * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR = 2117,
-
- /**
- * The transaction ID was used for a conflicing transaction before.
- * This response is
- * provided with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_PAY_DB_TRANSACTION_ID_CONFLICT = 2118,
-
- /**
- * The merchant failed to store the merchant's state with
- * respect to the transaction in its database. This response is
- * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_PAY_DB_STORE_TRANSACTION_ERROR = 2119,
-
- /**
- * The exchange failed to provide a valid response to
- * the merchant's /keys request.
- * This response is provided
- * with HTTP status code MHD_HTTP_SERVICE_UNAVAILABLE.
- */
- TALER_EC_PAY_EXCHANGE_KEYS_FAILURE = 2120,
-
- /**
- * The payment is too late, the offer has expired.
- * This response is
- * provided with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_PAY_OFFER_EXPIRED = 2121,
-
-
- /**
- * Integer overflow with specified timestamp argument detected.
- * This response is provided
- * with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_HISTORY_TIMESTAMP_OVERFLOW = 2200,
-
- /**
- * Failed to retrieve history from merchant database.
- * This response is provided
- * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_HISTORY_DB_FETCH_ERROR = 2201,
-
- /**
- * We failed to contact the exchange for the /track/transaction
- * request. This response is provided with HTTP status code
- * MHD_HTTP_SERVICE_UNAVAILABLE.
- */
- TALER_EC_DEPOSITS_GET_EXCHANGE_TIMEOUT = 2300,
-
- /**
- * The backend could not find the merchant instance specified
- * in the request. This response is
- * provided with HTTP status code MHD_HTTP_NOT_FOUND.
- */
- TALER_EC_DEPOSITS_GET_INSTANCE_UNKNOWN = 2301,
-
- /**
- * The backend could not find the transaction specified
- * in the request. This response is
- * provided with HTTP status code MHD_HTTP_NOT_FOUND.
- */
- TALER_EC_DEPOSITS_GET_TRANSACTION_UNKNOWN = 2302,
-
- /**
- * The backend had a database access error trying to
- * retrieve transaction data from its database.
- * The response is
- * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_DEPOSITS_GET_DB_FETCH_TRANSACTION_ERROR = 2303,
-
- /**
- * The backend had a database access error trying to
- * retrieve payment data from its database.
- * The response is
- * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_DEPOSITS_GET_DB_FETCH_PAYMENT_ERROR = 2304,
-
- /**
- * The backend found no applicable deposits in the database.
- * This is odd, as we know about the transaction, but not
- * about deposits we made for the transaction. The response is
- * provided with HTTP status code MHD_HTTP_NOT_FOUND.
- */
- TALER_EC_DEPOSITS_GET_DB_NO_DEPOSITS_ERROR = 2305,
-
- /**
- * We failed to obtain a wire transfer identifier for one
- * of the coins in the transaction. The response is
- * provided with HTTP status code MHD_HTTP_FAILED_DEPENDENCY if
- * the exchange had a hard error, or MHD_HTTP_ACCEPTED if the
- * exchange signaled that the transfer was in progress.
- */
- TALER_EC_DEPOSITS_GET_COIN_TRACE_ERROR = 2306,
-
- /**
- * We failed to obtain the full wire transfer identifier for the
- * transfer one of the coins was aggregated into.
- * The response is
- * provided with HTTP status code MHD_HTTP_FAILED_DEPENDENCY.
- */
- TALER_EC_DEPOSITS_GET_WIRE_TRANSFER_TRACE_ERROR = 2307,
-
- /**
- * We got conflicting reports from the exhange with
- * respect to which transfers are included in which
- * aggregate.
- * The response is
- * provided with HTTP status code MHD_HTTP_FAILED_DEPENDENCY.
- */
- TALER_EC_DEPOSITS_GET_CONFLICTING_REPORTS = 2308,
-
-
- /**
- * We failed to contact the exchange for the /track/transfer
- * request. This response is provided with HTTP status code
- * MHD_HTTP_SERVICE_UNAVAILABLE.
- */
- TALER_EC_TRANSFERS_GET_EXCHANGE_TIMEOUT = 2400,
-
- /**
- * The backend could not find the merchant instance specified
- * in the request. This response is
- * provided with HTTP status code MHD_HTTP_NOT_FOUND.
- */
- TALER_EC_TRANSFERS_GET_INSTANCE_UNKNOWN = 2401,
-
- /**
- * We failed to persist coin wire transfer information in
- * our merchant database.
- * The response is
- * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_TRANSFERS_GET_DB_STORE_COIN_ERROR = 2402,
-
- /**
- * We internally failed to execute the /track/transfer request.
- * The response is
- * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_TRANSFERS_GET_REQUEST_ERROR = 2403,
-
- /**
- * We failed to persist wire transfer information in
- * our merchant database.
- * The response is
- * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_TRANSFERS_GET_DB_STORE_TRANSFER_ERROR = 2404,
-
- /**
- * The exchange returned an error from /track/transfer.
- * The response is
- * provided with HTTP status code MHD_HTTP_FAILED_DEPENDENCY.
- */
- TALER_EC_TRANSFERS_GET_EXCHANGE_ERROR = 2405,
-
- /**
- * We failed to fetch deposit information from
- * our merchant database.
- * The response is
- * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_TRANSFERS_GET_DB_FETCH_DEPOSIT_ERROR = 2406,
-
- /**
- * We encountered an internal logic error.
- * The response is
- * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_TRANSFERS_GET_DB_INTERNAL_LOGIC_ERROR = 2407,
-
- /**
- * The exchange gave conflicting information about a coin which has
- * been wire transferred.
- * The response is provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_TRANSFERS_GET_CONFLICTING_REPORTS = 2408,
-
- /**
- * The hash provided in the request of /map/in does not match
- * the contract sent alongside in the same request.
- */
- TALER_EC_MAP_IN_UNMATCHED_HASH = 2500,
-
- /**
- * The backend encountered an error while trying to store the
- * pair <contract, h_proposal_data> into the database.
- * The response is provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_MAP_IN_STORE_DB_ERROR = 2501,
-
- /**
- * The backend encountered an error while trying to retrieve the
- * contract from the database. Likely to be an internal error.
- */
- TALER_EC_MAP_OUT_GET_FROM_DB_ERROR = 2502,
-
-
- /**
- * The backend encountered an error while trying to retrieve the
- * contract from the database. Likely to be an internal error.
- */
- TALER_EC_MAP_OUT_CONTRACT_UNKNOWN = 2503,
-
- /* ********** /test API error codes ************* */
-
- /**
- * The exchange failed to compute ECDH. This response is provided
- * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_TEST_ECDH_ERROR = 4000,
-
- /**
- * The EdDSA test signature is invalid. This response is provided
- * with HTTP status code MHD_HTTP_BAD_REQUEST.
- */
- TALER_EC_TEST_EDDSA_INVALID = 4001,
-
- /**
- * The exchange failed to compute the EdDSA test signature. This response is provided
- * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_TEST_EDDSA_ERROR = 4002,
-
- /**
- * The exchange failed to generate an RSA key. This response is provided
- * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_TEST_RSA_GEN_ERROR = 4003,
-
- /**
- * The exchange failed to compute the public RSA key. This response
- * is provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_TEST_RSA_PUB_ERROR = 4004,
-
- /**
- * The exchange failed to compute the RSA signature. This response
- * is provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_TEST_RSA_SIGN_ERROR = 4005,
-
-
- /**
- * End of error code range.
- */
- TALER_EC_END = 9999
- };
diff --git a/core/api-exchange.rst b/core/api-exchange.rst
index 3d8d8b7e..4c5be000 100644
--- a/core/api-exchange.rst
+++ b/core/api-exchange.rst
@@ -1,6 +1,6 @@
..
This file is part of GNU TALER.
- Copyright (C) 2014-2020 Taler Systems SA
+ Copyright (C) 2014-2024 Taler Systems SA
TALER 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
@@ -15,59 +15,21 @@
@author Christian Grothoff
-=============================
-The Exchange RESTful JSON API
-=============================
+========================
+The Exchange RESTful API
+========================
The API specified here follows the :ref:`general conventions <http-common>`
for all details not specified in the individual requests.
The `glossary <https://docs.taler.net/glossary.html#glossary>`_
defines all specific terms used in this section.
-.. _keys:
-
---------------------
-Terms of service API
---------------------
-
-These APIs allow merchants and wallets to obtain the terms of service
-and the privacy policy of an exchange.
-
-
-.. http:get:: /terms
-
- Get the terms of service of the exchange.
- The exchange will consider the "Accept" and "Accept-Language" and
- "Accept-Encoding" headers when generating a response. Specifically,
- it will try to find a response with an acceptable mime-type, then
- pick the version in the most preferred language of the user, and
- finally apply compression if that is allowed by the client and
- deemed beneficial.
-
- The exchange will set an "Etag", and subsequent requests of the
- same client should provide the tag in an "If-None-Match" header
- to detect if the terms of service have changed. If not, a
- "204 Not Modified" response will be returned.
-
- If the "Etag" is missing, the client should not cache the response and instead prompt the user again at the next opportunity. This is usually only the case if the terms of service were not configured correctly.
+.. contents:: Table of Contents
+ :local:
+.. include:: tos.rst
-.. http:get:: /privacy
-
- Get the privacy policy of the exchange.
- The exchange will consider the "Accept" and "Accept-Language" and
- "Accept-Encoding" headers when generating a response. Specifically,
- it will try to find a response with an acceptable mime-type, then
- pick the version in the most preferred language of the user, and
- finally apply compression if that is allowed by the client and
- deemed beneficial.
-
- The exchange will set an "Etag", and subsequent requests of the
- same client should provide the tag in an "If-None-Match" header
- to detect if the privacy policy has changed. If not, a
- "204 Not Modified" response will be returned.
-
- If the "Etag" is missing, the client should not cache the response and instead prompt the user again at the next opportunity. This is usually only the case if the privacy policy was not configured correctly.
+.. _keys:
---------------------------
Exchange status information
@@ -94,6 +56,75 @@ possibly by using HTTPS.
returned MUST be mixed with locally generated entropy.
+.. http:get:: /config
+
+ Return the protocol version and currency supported by this exchange backend,
+ as well as the list of possible KYC requirements. This endpoint is largely
+ for the SPA for AML officers. Merchants should use ``/keys`` which also
+ contains the protocol version and currency.
+ This specification corresponds to ``current`` protocol being **v19**.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The body is a `VersionResponse`.
+
+ .. ts:def:: ExchangeVersionResponse
+
+ interface ExchangeVersionResponse {
+ // 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;
+
+ // Name of the protocol.
+ name: "taler-exchange";
+
+ // URN of the implementation (needed to interpret 'revision' in version).
+ // @since **v18**, may become mandatory in the future.
+ implementation?: string;
+
+ // Currency supported by this exchange, given
+ // as a currency code ("USD" or "EUR").
+ currency: string;
+
+ // How wallets should render this currency.
+ currency_specification: CurrencySpecification;
+
+ // Names of supported KYC requirements.
+ supported_kyc_requirements: string[];
+
+ }
+
+ .. ts:def:: CurrencySpecification
+
+ interface CurrencySpecification {
+ // Name of the currency. Like "US Dollar".
+ name: string;
+
+ // Code of the currency.
+ // Deprecated in protocol **v18** for the exchange
+ // and in protocol v6 for the merchant.
+ currency: string;
+
+ // how many digits the user may enter after the decimal_separator
+ num_fractional_input_digits: Integer;
+
+ // Number of fractional digits to render in normal font and size.
+ num_fractional_normal_digits: Integer;
+
+ // Number of fractional digits to render always, if needed by
+ // padding with zeros.
+ num_fractional_trailing_zero_digits: Integer;
+
+ // map of powers of 10 to alternative currency names / symbols, must
+ // always have an entry under "0" that defines the base name,
+ // e.g. "0 => €" or "3 => k€". For BTC, would be "0 => BTC, -3 => mBTC".
+ // Communicates the currency symbol to be used.
+ alt_unit_names: { log10 : string };
+ }
+
+
.. http:get:: /keys
Get a list of all denomination keys offered by the exchange,
@@ -120,9 +151,55 @@ possibly by using HTTPS.
// The format is "current:revision:age".
version: string;
- // The exchange's currency.
+ // The exchange's base URL.
+ base_url: string;
+
+ // The exchange's currency or asset unit.
currency: string;
+ // How wallets should render this currency.
+ currency_specification: CurrencySpecification;
+
+ // Absolute cost offset for the STEFAN curve used
+ // to (over) approximate fees payable by amount.
+ stefan_abs: Amount;
+
+ // Factor to multiply the logarithm of the amount
+ // with to (over) approximate fees payable by amount.
+ // Note that the total to be paid is first to be
+ // divided by the smallest denomination to obtain
+ // the value that the logarithm is to be taken of.
+ stefan_log: Amount;
+
+ // Linear cost factor for the STEFAN curve used
+ // to (over) approximate fees payable by amount.
+ //
+ // Note that this is a scalar, as it is multiplied
+ // with the actual amount.
+ stefan_lin: Float;
+
+ // Type of the asset. "fiat", "crypto", "regional"
+ // or "stock". Wallets should adjust their UI/UX
+ // based on this value.
+ asset_type: string;
+
+ // Array of wire accounts operated by the exchange for
+ // incoming wire transfers.
+ accounts: WireAccount[];
+
+ // Object mapping names of wire methods (i.e. "iban" or "x-taler-bank")
+ // to wire fees.
+ wire_fees: { method : AggregateTransferFee[] };
+
+ // List of exchanges that this exchange is partnering
+ // with to enable wallet-to-wallet transfers.
+ wads: ExchangePartner[];
+
+ // Set to true if this exchange allows the use
+ // of reserves for rewards.
+ // @deprecated in protocol **v18**.
+ rewards_allowed: false;
+
// EdDSA master public key of the exchange, used to sign entries
// in ``denoms`` and ``signkeys``.
master_public_key: EddsaPublicKey;
@@ -131,16 +208,32 @@ possibly by using HTTPS.
// not signed (!), can change without notice.
reserve_closing_delay: RelativeTime;
- // Denominations offered by this exchange.
- denoms: Denom[];
+ // Threshold amounts beyond which wallet should
+ // trigger the KYC process of the issuing
+ // exchange. Optional option, if not given there is no limit.
+ // Currency must match ``currency``.
+ wallet_balance_limit_without_kyc?: Amount[];
+
+ // Denominations offered by this exchange
+ denominations: DenomGroup[];
+
+ // Compact EdDSA `signature` (binary-only) over the
+ // contatentation of all of the master_sigs (in reverse
+ // chronological order by group) in the arrays under
+ // "denominations". Signature of `TALER_ExchangeKeySetPS`
+ exchange_sig: EddsaSignature;
+
+ // Public EdDSA key of the exchange that was used to generate the signature.
+ // Should match one of the exchange's signing keys from ``signkeys``. It is given
+ // explicitly as the client might otherwise be confused by clock skew as to
+ // which signing key was used for the ``exchange_sig``.
+ exchange_pub: EddsaPublicKey;
// Denominations for which the exchange currently offers/requests recoup.
recoup: Recoup[];
- // Fees relevant for wallet-to-wallet (or peer-to-peer) payments.
- // If no fees are provided for a given time range, then the
- // exchange simply does not support purses/p2p-payments at that time.
- p2p_fees: P2PFees[];
+ // Array of globally applicable fees by time range.
+ global_fees: GlobalFees[];
// The date when the denomination keys were last updated.
list_issue_date: Timestamp;
@@ -151,28 +244,104 @@ possibly by using HTTPS.
// The exchange's signing keys.
signkeys: SignKey[];
- // Compact EdDSA `signature` (binary-only) over the SHA-512 hash of the
- // concatenation of all SHA-512 hashes of the RSA denomination public keys
- // in ``denoms`` in the same order as they were in ``denoms``. Note that for
- // hashing, the binary format of the RSA public keys is used, and not their
- // `base32 encoding <base32>`. Wallets cannot do much with this signature by itself;
- // it is only useful when multiple clients need to establish that the exchange
- // is sabotaging end-user anonymity by giving disjoint denomination keys to
- // different users. If an exchange were to do this, this signature allows the
- // clients to demonstrate to the public that the exchange is dishonest.
- // Signature of `TALER_ExchangeKeySetPS`
- eddsa_sig: EddsaSignature;
+ // Optional field with a dictionary of (name, object) pairs defining the
+ // supported and enabled extensions, such as ``age_restriction``.
+ extensions?: { name: ExtensionManifest };
+
+ // Signature by the exchange master key of the SHA-256 hash of the
+ // normalized JSON-object of field extensions, if it was set.
+ // The signature has purpose TALER_SIGNATURE_MASTER_EXTENSIONS.
+ extensions_sig?: EddsaSignature;
+
+ }
+
+ The specification for the account object is:
+
+ .. ts:def:: WireAccount
+
+ interface WireAccount {
+ // ``payto://`` URI identifying the account and wire method
+ payto_uri: string;
+
+ // URI to convert amounts from or to the currency used by
+ // this wire account of the exchange. Missing if no
+ // conversion is applicable.
+ conversion_url?: string;
+
+ // Restrictions that apply to bank accounts that would send
+ // funds to the exchange (crediting this exchange bank account).
+ // Optional, empty array for unrestricted.
+ credit_restrictions: AccountRestriction[];
+
+ // Restrictions that apply to bank accounts that would receive
+ // funds from the exchange (debiting this exchange bank account).
+ // Optional, empty array for unrestricted.
+ debit_restrictions: AccountRestriction[];
+
+ // Signature using the exchange's offline key over
+ // a `TALER_MasterWireDetailsPS`
+ // with purpose ``TALER_SIGNATURE_MASTER_WIRE_DETAILS``.
+ master_sig: EddsaSignature;
+
+ // Display label wallets should use to show this
+ // bank account.
+ // Since protocol **v19**.
+ bank_label?: string;
+
+ // *Signed* integer with the display priority for
+ // this bank account. Optional, 0 if missing.
+ // Since protocol **v19**.
+ priority?: Integer;
+
+ }
+
+ .. ts:def:: AccountRestriction
+
+ type AccountRestriction =
+ | RegexAccountRestriction
+ | DenyAllAccountRestriction
+
+ .. ts:def:: DenyAllAccountRestriction
+
+ // Account restriction that disables this type of
+ // account for the indicated operation categorically.
+ interface DenyAllAccountRestriction {
+
+ type: "deny";
+ }
+
+ .. ts:def:: RegexAccountRestriction
+
+ // Accounts interacting with this type of account
+ // restriction must have a payto://-URI matching
+ // the given regex.
+ interface RegexAccountRestriction {
+
+ type: "regex";
+
+ // Regular expression that the payto://-URI of the
+ // partner account must follow. The regular expression
+ // should follow posix-egrep, but without support for character
+ // classes, GNU extensions, back-references or intervals. See
+ // https://www.gnu.org/software/findutils/manual/html_node/find_html/posix_002degrep-regular-expression-syntax.html
+ // for a description of the posix-egrep syntax. Applications
+ // may support regexes with additional features, but exchanges
+ // must not use such regexes.
+ payto_regex: string;
+
+ // Hint for a human to understand the restriction
+ // (that is hopefully easier to comprehend than the regex itself).
+ human_hint: string;
+
+ // Map from IETF BCP 47 language tags to localized
+ // human hints.
+ human_hint_i18n?: { [lang_tag: string]: string };
- // Public EdDSA key of the exchange that was used to generate the signature.
- // Should match one of the exchange's signing keys from ``/keys``. It is given
- // explicitly as the client might otherwise be confused by clock skew as to
- // which signing key was used.
- eddsa_pub: EddsaPublicKey;
}
- .. ts:def:: P2PFees
+ .. ts:def:: GlobalFees
- interface P2PFees {
+ interface GlobalFees {
// What date (inclusive) does these fees go into effect?
start_date: Timestamp;
@@ -180,15 +349,9 @@ possibly by using HTTPS.
// What date (exclusive) does this fees stop going into effect?
end_date: Timestamp;
- // KYC fee, charged when a user wants to create an account.
- // The first year of the account_annual_fee after the KYC is
- // always included.
- kyc_fee: Amount;
-
// Account history fee, charged when a user wants to
- // obtain the full account history, and not just the
- // recent transactions in an account.
- account_history_fee: Amount;
+ // obtain a reserve/account history.
+ history_fee: Amount;
// Annual fee charged for having an open account at the
// exchange. Charged to the account. If the account
@@ -196,24 +359,17 @@ possibly by using HTTPS.
// is automatically deleted/closed. (Note that the exchange
// will keep the account history around for longer for
// regulatory reasons.)
- account_annual_fee: Amount;
-
- // How long will the exchange preserve the account history?
- // After an account was deleted/closed, the exchange will
- // retain the account history for legal reasons until this time.
- legal_history_retention: RelativeTime;
-
- // How long does the exchange promise to keep funds
- // an account for which the KYC has never happened
- // after a purse was merged into an account? Basically,
- // after this time funds in an account without KYC are
- // forfeit.
- account_kyc_timeout: RelativeTime;
+ account_fee: Amount;
// Purse fee, charged only if a purse is abandoned
// and was not covered by the account limit.
purse_fee: Amount;
+ // How long will the exchange preserve the account history?
+ // After an account was deleted/closed, the exchange will
+ // retain the account history for legal reasons until this time.
+ history_expiration: RelativeTime;
+
// Non-negative number of concurrent purses that any
// account holder is allowed to create without having
// to pay the purse_fee.
@@ -225,31 +381,83 @@ possibly by using HTTPS.
// plus this value.
purse_timeout: RelativeTime;
- // Signature of `TALER_P2PFeesPS`.
+ // Signature of `TALER_GlobalFeesPS`.
master_sig: EddsaSignature;
}
- .. ts:def:: Denom
+ .. ts:def:: AgeMask
+
+ // Binary representation of the age groups.
+ // The bits set in the mask mark the edges at the beginning of a next age
+ // group. F.e. for the age groups
+ // 0-7, 8-9, 10-11, 12-13, 14-15, 16-17, 18-21, 21-*
+ // the following bits are set:
+ //
+ // 31 24 16 8 0
+ // | | | | |
+ // oooooooo oo1oo1o1 o1o1o1o1 ooooooo1
+ //
+ // A value of 0 means that the exchange does not support the extension for
+ // age-restriction.
+ type AgeMask = Integer;
+
+ .. ts:def:: DenomGroup
+
+ type DenomGroup =
+ | DenomGroupRsa
+ | DenomGroupCs
+ | DenomGroupRsaAgeRestricted
+ | DenomGroupCsAgeRestricted;
+
+ .. ts:def:: DenomGroupRsa
+
+ interface DenomGroupRsa extends DenomGroupCommon {
+ cipher: "RSA";
+
+ denoms: ({
+ rsa_pub: RsaPublicKey;
+ } & DenomCommon)[];
+ }
- interface Denom {
- // How much are coins of this denomination worth?
- value: Amount;
+ .. ts:def:: DenomGroupCs
- // When does the denomination key become valid?
- stamp_start: Timestamp;
+ interface DenomGroupCs extends DenomGroupCommon {
+ cipher: "CS";
- // When is it no longer possible to deposit coins
- // of this denomination?
- stamp_expire_withdraw: Timestamp;
+ denoms: ({
+ cs_pub: Cs25519Point;
+ } & DenomCommon)[];
+ }
- // Timestamp indicating by when legal disputes relating to these coins must
- // be settled, as the exchange will afterwards destroy its evidence relating to
- // transactions involving this coin.
- stamp_expire_legal: Timestamp;
+ .. ts:def:: DenomGroupRsaAgeRestricted
- // Public (RSA) key for the denomination.
- denom_pub: RsaPublicKey;
+ interface DenomGroupRsaAgeRestricted extends DenomGroupCommon {
+ cipher: "RSA+age_restricted";
+ age_mask: AgeMask;
+
+ denoms: ({
+ rsa_pub: RsaPublicKey;
+ } & DenomCommon)[];
+ }
+
+ .. ts:def:: DenomGroupCsAgeRestricted
+
+ interface DenomGroupCSAgeRestricted extends DenomGroupCommon {
+ cipher: "CS+age_restricted";
+ age_mask: AgeMask;
+
+ denoms: ({
+ cs_pub: Cs25519Point;
+ } & DenomCommon)[];
+ }
+
+ .. ts:def:: DenomGroupCommon
+
+ // Common attributes for all denomination groups
+ interface DenomGroupCommon {
+ // How much are coins of this denomination worth?
+ value: Amount;
// Fee charged by the exchange for withdrawing a coin of this denomination.
fee_withdraw: Amount;
@@ -263,8 +471,69 @@ possibly by using HTTPS.
// Fee charged by the exchange for refunding a coin of this denomination.
fee_refund: Amount;
+ }
+
+ .. ts:def:: DenomCommon
+
+ interface DenomCommon {
// Signature of `TALER_DenominationKeyValidityPS`.
master_sig: EddsaSignature;
+
+ // When does the denomination key become valid?
+ stamp_start: Timestamp;
+
+ // When is it no longer possible to withdraw coins
+ // of this denomination?
+ stamp_expire_withdraw: Timestamp;
+
+ // When is it no longer possible to deposit coins
+ // of this denomination?
+ stamp_expire_deposit: Timestamp;
+
+ // Timestamp indicating by when legal disputes relating to these coins must
+ // be settled, as the exchange will afterwards destroy its evidence relating to
+ // transactions involving this coin.
+ stamp_expire_legal: Timestamp;
+
+ // Set to 'true' if the exchange somehow "lost"
+ // the private key. The denomination was not
+ // necessarily revoked, but still cannot be used
+ // to withdraw coins at this time (theoretically,
+ // the private key could be recovered in the
+ // future; coins signed with the private key
+ // remain valid).
+ lost?: boolean;
+ }
+
+ .. ts:def:: DenominationKey
+
+ type DenominationKey =
+ | RsaDenominationKey
+ | CSDenominationKey;
+
+ .. ts:def:: RsaDenominationKey
+
+ interface RsaDenominationKey {
+ cipher: "RSA";
+
+ // 32-bit age mask.
+ age_mask: Integer;
+
+ // RSA public key
+ rsa_public_key: RsaPublicKey;
+ }
+
+ .. ts:def:: CSDenominationKey
+
+ interface CSDenominationKey {
+ cipher: "CS";
+
+ // 32-bit age mask.
+ age_mask: Integer;
+
+ // Public key of the denomination.
+ cs_public_key: Cs25519Point;
+
}
Fees for any of the operations can be zero, but the fields must still be
@@ -357,53 +626,6 @@ possibly by using HTTPS.
Both the individual denominations *and* the denomination list is signed,
allowing customers to prove that they received an inconsistent list.
-.. _wire-req:
-
-.. http:get:: /wire
-
- Returns a list of payment methods supported by the exchange. The idea is that wallets may use this information to instruct users on how to perform wire transfers to top up their wallets.
-
- **Response:**
-
- :http:statuscode:`200 Ok`:
- The exchange responds with a `WireResponse` object. This request should virtually always be successful.
-
- **Details:**
-
- .. ts:def:: WireResponse
-
- interface WireResponse {
-
- // Master public key of the exchange, must match the key returned in ``/keys``.
- master_public_key: EddsaPublicKey;
-
- // Array of wire accounts operated by the exchange for
- // incoming wire transfers.
- accounts: WireAccount[];
-
- // Object mapping names of wire methods (i.e. "sepa" or "x-taler-bank")
- // to wire fees.
- fees: { method : AggregateTransferFee };
-
- // List of exchanges that this exchange is partnering
- // with to enable wallet-to-wallet transfers.
- wads: ExchangePartner[];
- }
-
- The specification for the account object is:
-
- .. ts:def:: WireAccount
-
- interface WireAccount {
- // ``payto://`` URI identifying the account and wire method
- payto_uri: string;
-
- // Signature using the exchange's offline key over
- // a `TALER_MasterWireDetailsPS`
- // with purpose ``TALER_SIGNATURE_MASTER_WIRE_DETAILS``.
- master_sig: EddsaSignature;
- }
-
Aggregate wire transfer fees representing the fees the exchange
charges per wire transfer to a merchant must be specified as an
array in all wire transfer response objects under ``fees``. The
@@ -442,7 +664,7 @@ possibly by using HTTPS.
// Public master key of the partner exchange.
partner_master_pub: EddsaPublicKey;
- // Wallet-to-wallet transfer wad fee charged.
+ // Per exchange-to-exchange transfer (wad) fee.
wad_fee: Amount;
// Exchange-to-exchange wad (wire) transfer frequency.
@@ -529,8 +751,8 @@ Management operations authorized by master key
// transactions involving this coin.
stamp_expire_legal: Timestamp;
- // Public (RSA) key for the denomination.
- denom_pub: RsaPublicKey;
+ // Public key for the denomination.
+ denom_pub: DenominationKey;
// Fee charged by the exchange for withdrawing a coin of this denomination.
fee_withdraw: Amount;
@@ -611,7 +833,7 @@ Management operations authorized by master key
interface DenomSignature {
- // Hash of the public (RSA) key of the denomination.
+ // Hash of the public key of the denomination.
h_denom_pub: HashCode;
// Signature over `TALER_DenominationKeyValidityPS`.
@@ -786,7 +1008,7 @@ Management operations authorized by master key
.. http:post:: /management/wire-fee
- This request will be used to configure wire fees.
+ This request is used to configure wire fees.
**Request:**
@@ -828,6 +1050,23 @@ Management operations authorized by master key
}
+.. http:post:: /management/global-fees
+
+ Provides global fee configuration for a timeframe.
+
+ **Request:**
+
+ The request must be a `GlobalFees` message.
+
+ **Response**
+
+ :http:statuscode:`204 No content`:
+ The configuration update has been processed successfully. The body is empty.
+ :http:statuscode:`403 Forbidden`:
+ The signature is invalid.
+ :http:statuscode:`409 Conflict`:
+ The exchange has previously received a conflicting configuration message.
+
.. http:post:: /management/wire
@@ -874,6 +1113,16 @@ Management operations authorized by master key
// become active immediately! Used ONLY to detect replay attacks.
validity_start: Timestamp;
+ // Display label wallets should use to show this
+ // bank account.
+ // Since protocol **v19**.
+ bank_label?: string;
+
+ // *Signed* integer with the display priority for
+ // this bank account.
+ // Since protocol **v19**.
+ priority?: Integer;
+
}
.. http:post:: /management/wire/disable
@@ -924,27 +1173,102 @@ Management operations authorized by master key
}
-.. http:post:: /management/p2pfees
+.. http:post:: /management/drain
- Provides fee configuration for purses.
+ This request is used to drain profits from the
+ exchange's escrow account to another regular
+ bank account of the exchange. The actual drain
+ requires running the ``taler-exchange-drain`` tool.
**Request:**
- The request must be a `P2PFees` message.
+ The request must be a `DrainProfitsMessage`.
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The profit drain was scheduled.
+ :http:statuscode:`403 Forbidden`:
+ The master signature is invalid.
+
+ **Details:**
+
+ .. ts:def:: DrainProfitsMessage
+
+ interface DrainProfitsMessage {
+
+ // Configuration section of the account to debit.
+ debit_account_section: string;
+
+ // Credit payto URI
+ credit_payto_uri: string;
+
+ // Wire transfer identifier to use.
+ wtid: Base32;
+
+ // Signature by the exchange master key over a
+ // `TALER_MasterDrainProfitPS`.
+ // Must have purpose ``TALER_SIGNATURE_MASTER_DRAIN_PROFITS``.
+ master_sig: EddsaSignature;
+
+ // When was the message created.
+ date: Timestamp;
+
+ // Amount to be drained.
+ amount: Amount;
+
+ }
+
+
+.. http:post:: /management/aml-officers
+
+ Update settings for an AML Officer status.
+
+ **Request:**
+
+ The request must be an `AmlOfficerSetup` message.
**Response**
:http:statuscode:`204 No content`:
- The configuration update has been processed successfully. The body is empty.
+ The officer settings have been updated successfully.
:http:statuscode:`403 Forbidden`:
The signature is invalid.
:http:statuscode:`409 Conflict`:
The exchange has previously received a conflicting configuration message.
+ **Details:**
+
+ .. ts:def:: AmlOfficerSetup
+
+ interface AmlOfficerSetup {
+
+ // Public key of the AML officer
+ officer_pub: EddsaPublicKey;
-.. http:post:: /management/partners
+ // Legal full name of the AML officer
+ officer_name: string;
- Enables a partner exchange for wad transfers.
+ // Is the account active?
+ is_active: boolean;
+
+ // Is the account read-only?
+ read_only: boolean;
+
+ // Signature by the exchange master key over a
+ // `TALER_MasterAmlOfficerStatusPS`.
+ // Must have purpose ``TALER_SIGNATURE_MASTER_AML_KEY``.
+ master_sig: EddsaSignature;
+
+ // When will the change take effect?
+ change_date: Timestamp;
+
+ }
+
+
+ .. http:post:: /management/partners
+
+ Enables a partner exchange for wad transfers.
**Request:**
@@ -959,7 +1283,233 @@ Management operations authorized by master key
:http:statuscode:`409 Conflict`:
The exchange has previously received a conflicting configuration message.
+ **Details:**
+
+ .. ts:def:: ExchangePartner
+
+ interface ExchangePartner {
+
+ // Base URL of the partner exchange
+ partner_base_url: string;
+
+ // Master (offline) public key of the partner exchange.
+ partner_pub: EddsaPublicKey;
+
+ // How frequently will wad transfers be made
+ wad_frequency: RelativeTime;
+
+ // Signature by the exchange master key over a
+ // `TALER_PartnerConfigurationPS`.
+ // Must have purpose ``TALER_SIGNATURE_MASTER_PARTNER_DETAILS``.
+ master_sig: EddsaSignature;
+
+ // When will the partner relationship start (inclusive).
+ start_date: Timestamp;
+
+ // When will the partner relationship end (exclusive).
+ end_date: Timestamp;
+
+ // Wad fee to be charged (to customers).
+ wad_fee: Amount;
+
+ }
+
+--------------
+AML operations
+--------------
+
+This API is only for designated AML officers. It is used
+to allow exchange staff to monitor suspicious transactions
+and freeze or unfreeze accounts suspected of money laundering.
+
+
+.. http:get:: /aml/$OFFICER_PUB/decisions/$STATE
+
+ Obtain list of AML decisions (filtered by $STATE). ``$STATE`` must be either ``normal``, ``pending`` or ``frozen``.
+
+ *Taler-AML-Officer-Signature*: The client must provide Base-32 encoded EdDSA signature with ``$OFFICER_PRIV``, affirming the desire to obtain AML data. Note that this is merely a simple authentication mechanism, the details of the request are not protected by the signature.
+
+ :query delta: *Optional*. takes value of the form ``N (-N)``, so that at most ``N`` values strictly older (younger) than ``start`` are returned. Defaults to ``-20`` to return the last 20 entries (before ``start``).
+ :query start: *Optional*. Row number threshold, see ``delta`` for its interpretation. Defaults to ``INT64_MAX``, namely the biggest row id possible in the database.
+
+ **Response**
+
+ :http:statuscode:`200 OK`:
+ The responds will be an `AmlRecords` message.
+ :http:statuscode:`204 No content`:
+ There are no matching AML records.
+ :http:statuscode:`403 Forbidden`:
+ The signature is invalid.
+ :http:statuscode:`404 Not found`:
+ The designated AML account is not known.
+ :http:statuscode:`409 Conflict`:
+ The designated AML account is not enabled.
+
+ **Details:**
+
+ .. ts:def:: AmlRecords
+
+ interface AmlRecords {
+
+ // Array of AML records matching the query.
+ records: AmlRecord[];
+ }
+
+ .. ts:def:: AmlRecord
+
+ interface AmlRecord {
+
+ // Which payto-address is this record about.
+ // Identifies a GNU Taler wallet or an affected bank account.
+ h_payto: PaytoHash;
+
+ // What is the current AML state.
+ current_state: Integer;
+
+ // Monthly transaction threshold before a review will be triggered
+ threshold: Amount;
+
+ // RowID of the record.
+ rowid: Integer;
+
+ }
+
+
+.. http:get:: /aml/$OFFICER_PUB/decision/$H_PAYTO
+
+ Obtain deails about an AML decision.
+
+ *Taler-AML-Officer-Signature*: The client must provide Base-32 encoded EdDSA signature with ``$OFFICER_PRIV``, affirming the desire to obtain AML data. Note that this is merely a simple authentication mechanism, the details of the request are not protected by the signature.
+
+ :query history: *Optional*. If set to yes, we return all historic decisions and not only the last one.
+
+ **Response**
+
+ :http:statuscode:`200 OK`:
+ The responds will be an `AmlDecisionDetails` message.
+ :http:statuscode:`204 No content`:
+ There are no matching AML records for the given payto://-URI.
+ :http:statuscode:`403 Forbidden`:
+ The signature is invalid.
+ :http:statuscode:`404 Not found`:
+ The designated AML account is not known.
+ :http:statuscode:`409 Conflict`:
+ The designated AML account is not enabled.
+
+ **Details:**
+
+ .. ts:def:: AmlDecisionDetails
+
+ interface AmlDecisionDetails {
+
+ // Array of AML decisions made for this account. Possibly
+ // contains only the most recent decision if "history" was
+ // not set to 'true'.
+ aml_history: AmlDecisionDetail[];
+
+ // Array of KYC attributes obtained for this account.
+ kyc_attributes: KycDetail[];
+ }
+
+ .. ts:def:: AmlDecisionDetail
+
+ interface AmlDecisionDetail {
+
+ // What was the justification given?
+ justification: string;
+
+ // FIXME: review!
+ // What is the new AML state.
+ new_state: Integer;
+
+ // When was this decision made?
+ decision_time: Timestamp;
+
+ // What is the new AML decision threshold (in monthly transaction volume)?
+ new_threshold: Amount;
+
+ // Who made the decision?
+ decider_pub: AmlOfficerPublicKeyP;
+
+ }
+
+ .. ts:def:: KycDetail
+
+ interface KycDetail {
+
+ // Name of the configuration section that specifies the provider
+ // which was used to collect the KYC details
+ // FIXME: review!
+ provider_section: string;
+
+ // The collected KYC data. NULL if the attribute data could not
+ // be decrypted (internal error of the exchange, likely the
+ // attribute key was changed).
+ attributes?: Object;
+
+ // Time when the KYC data was collected
+ collection_time: Timestamp;
+
+ // Time when the validity of the KYC data will expire
+ expiration_time: Timestamp;
+
+ }
+
+
+ .. http:post:: /aml/$OFFICER_PUB/decision
+
+ Make an AML decision. Triggers the respective action and
+ records the justification.
+
+ **Request:**
+
+ The request must be an `AmlDecision` message.
+
+ **Response**
+
+ :http:statuscode:`204 No content`:
+ The AML decision has been executed and recorded successfully.
+ :http:statuscode:`403 Forbidden`:
+ The signature is invalid.
+ :http:statuscode:`404 Not found`:
+ The address the decision was made upon is unknown to the exchange or
+ the designated AML account is not known.
+ :http:statuscode:`409 Conflict`:
+ The designated AML account is not enabled or a more recent
+ decision was already submitted.
+
+ **Details:**
+
+ .. ts:def:: AmlDecision
+
+ interface AmlDecision {
+
+ // Human-readable justification for the decision.
+ justification: string;
+
+ // At what monthly transaction volume should the
+ // decision be automatically reviewed?
+ new_threshold: Amount;
+ // Which payto-address is the decision about?
+ // Identifies a GNU Taler wallet or an affected bank account.
+ h_payto: PaytoHash;
+
+ // What is the new AML state (e.g. frozen, unfrozen, etc.)
+ // Numerical values are defined in `AmlDecisionState`.
+ new_state: Integer;
+
+ // Signature by the AML officer over a `TALER_AmlDecisionPS`.
+ // Must have purpose ``TALER_SIGNATURE_MASTER_AML_KEY``.
+ officer_sig: EddsaSignature;
+
+ // When was the decision made?
+ decision_time: Timestamp;
+
+ // Optional argument to impose new KYC requirements
+ // that the customer has to satisfy to unblock transactions.
+ kyc_requirements?: string[];
+ }
---------------
@@ -1034,6 +1584,7 @@ This part of the API is for the use by auditors interacting with the exchange.
}
+.. _exchange-withdrawal:
----------
Withdrawal
@@ -1050,362 +1601,301 @@ exchange.
.. note::
- Eventually the exchange will need to advertize a policy for how long it will
+ Eventually the exchange will need to advertise a policy for how long it will
keep transaction histories for inactive or even fully drained reserves. We
will therefore need some additional handler similar to ``/keys`` to
- advertize those terms of service.
+ advertise those terms of service.
-.. http:post:: /reserves/$RESERVE_PUB/status
+.. http:get:: /reserves/$RESERVE_PUB
- Request information about a reserve or an account.
+ Request summary information about a reserve.
**Request:**
- :query history=BOOLEAN: *Optional.* If specified, the exchange
- will return the recent account history.
- This is still free of charge.
- :query full_history=BOOLEAN: *Optional.* If 'true' is specified,
- the exchange will return the full account history. This
- may incur a fee that will be charged to the account.
-
- The request body must be a `ReserveStatusRequest` object.
+ :query timeout_ms=MILLISECONDS: *Optional.* If specified, the exchange will wait up to MILLISECONDS for incoming funds before returning a 404 if the reserve does not yet exist.
**Response:**
:http:statuscode:`200 OK`:
- The exchange responds with a `ReserveStatus` object; the reserve was known to the exchange.
- :http:statuscode:`401 Unauthorized`:
- The *Account-Request-Signature* is invalid.
- This response comes with a standard `ErrorDetail` response.
- :http:statuscode:`403 Forbidden`:
- The provided timestamp is not close to the current time.
+ The exchange responds with a `ReserveSummary` object; the reserve was known to the exchange.
:http:statuscode:`404 Not found`:
The reserve key does not belong to a reserve known to the exchange.
**Details:**
- .. ts:def:: ReserveStatusRequest
-
- interface ReserveStatusRequest {
- // Signature of purpose
- // ``TALER_SIGNATURE_RESERVE_STATUS_REQUEST`` over
- // a `TALER_ReserveStatusRequestSignaturePS`.
- reserve_sig: EddsaSignature;
-
- // Time when the client made the request.
- // Timestamp must be reasonably close to the time of
- // the exchange, otherwise the exchange may reject
- // the request.
- request_timestamp: Timestamp;
- }
-
- .. ts:def:: ReserveStatus
+ .. ts:def:: ReserveSummary
- interface ReserveStatus {
+ interface ReserveSummary {
// Balance left in the reserve.
balance: Amount;
- // True if the owner of the account currently satisfies
- // the required KYC checks.
- kyc_passed: boolean;
-
- // True if the reserve history includes a merge of a purse
- // and thus the owner must pass KYC checks before withdrawing.
- kyc_required: boolean;
-
- // Transaction history for this reserve.
- // May be partial (!).
- history: TransactionHistoryItem[];
+ // If set, age restriction is required to be set for each coin to this
+ // value during the withdrawal from this reserve. The client then MUST
+ // use a denomination with support for age restriction enabled for the
+ // withdrawal.
+ // The value represents a valid age group from the list of permissible
+ // age groups as defined by the exchange's output to /keys.
+ maximum_age_group?: number;
}
- Objects in the transaction history have the following format:
-
- .. ts:def:: TransactionHistoryItem
- // Union discriminated by the "type" field.
- type TransactionHistoryItem =
- | AccountMergeTransaction
- | AccountSetupTransaction
- | ReserveHistoryTransaction
- | ReserveWithdrawTransaction
- | ReserveCreditTransaction
- | ReserveClosingTransaction
- | ReserveRecoupTransaction;
+Withdraw
+~~~~~~~~
- .. ts:def:: ReserveHistoryTransaction
+.. http:post:: /csr-withdraw
- interface ReserveHistoryTransaction {
- type: "HISTORY";
+ Obtain exchange-side input values in preparation for a
+ withdraw step for certain denomination cipher types,
+ specifically at this point for Clause-Schnorr blind
+ signatures.
- // Fee agreed to by the reserve owner.
- history_fee: Amount;
+ **Request:** The request body must be a `WithdrawPrepareRequest` object.
- // Time when the request was made.
- request_timestamp: Timestamp;
-
- // Signature created with the reserve's private key.
- // Must be of purpose ``TALER_SIGNATURE_RESERVE_HISTORY_REQUEST`` over
- // a `TALER_ReserveHistoryRequestSignaturePS`.
- reserve_sig: EddsaSignature;
-
- }
+ **Response:**
- .. ts:def:: AccountSetupTransaction
+ :http:statuscode:`200 OK`:
+ The request was successful, and the response is a `WithdrawPrepareResponse`. Note that repeating exactly the same request
+ will again yield the same response (assuming none of the denomination is expired).
+ :http:statuscode:`404 Not found`:
+ The denomination key is not known to the exchange.
+ :http:statuscode:`410 Gone`:
+ The requested denomination key is not yet or no longer valid.
+ It either before the validity start, past the expiration or was revoked. The response is a
+ `DenominationExpiredMessage`. Clients must evaluate
+ the error code provided to understand which of the
+ cases this is and handle it accordingly.
- interface AccountSetupTransaction {
- type: "SETUP";
+ **Details:**
- // KYC fee agreed to by the reserve owner.
- kyc_fee: Amount;
+ .. ts:def:: WithdrawPrepareRequest
- // Time when the KYC was triggered.
- kyc_timestamp: Timestamp;
+ interface WithdrawPrepareRequest {
- // Hash of the wire details of the account.
- // Note that this hash is unsalted and potentially
- // private (as it could be inverted), hence access
- // to this endpoint must be authorized using the
- // private key of the reserve.
- h_wire: HashCode;
+ // Nonce to be used by the exchange to derive
+ // its private inputs from. Must not have ever
+ // been used before.
+ nonce: CSNonce;
- // Signature created with the reserve's private key.
- // Must be of purpose ``TALER_SIGNATURE_ACCOUNT_SETUP_REQUEST`` over
- // a `TALER_AccountSetupRequestSignaturePS`.
- reserve_sig: EddsaSignature;
+ // Hash of the public key of the denomination the
+ // request relates to.
+ denom_pub_hash: HashCode;
}
- .. ts:def:: AccountMergeTransaction
-
- interface AccountMergeTransaction {
- type: "MERGE";
+ .. ts:def:: WithdrawPrepareResponse
- // Actual amount merged (what was left after fees).
- amount: Amount;
+ type WithdrawPrepareResponse =
+ | ExchangeWithdrawValue;
- // Minimum amount merged (amount signed by the
- // reserve and purse signatures).
- minimum_amount: Amount;
+ .. ts:def:: ExchangeWithdrawValue
- // Purse that was merged.
- purse_pub: EddsaPublicKey;
+ type ExchangeWithdrawValue =
+ | ExchangeRsaWithdrawValue
+ | ExchangeCsWithdrawValue;
- // Time of the merge.
- merge_timestamp: Timestamp;
+ .. ts:def:: ExchangeRsaWithdrawValue
- // Expiration time of the purse.
- purse_expiration: Timestamp;
+ interface ExchangeRsaWithdrawValue {
+ cipher: "RSA";
+ }
- // Hash of the contract.
- h_contract: HashCode;
+ .. ts:def:: ExchangeCsWithdrawValue
- // Hash of the wire details of the reserve.
- h_wire: HashCode;
+ interface ExchangeCsWithdrawValue {
+ cipher: "CS";
- // Signature created with the reserve's private key.
- // Must be of purpose ``TALER_SIGNATURE_ACCOUNT_MERGE`` over
- // a `TALER_AccountMergeSignaturePS`.
- reserve_sig: EddsaSignature;
+ // CSR R0 value
+ r_pub_0: CsRPublic;
- // Signature created with the purse's private key.
- // Must be of purpose ``TALER_SIGNATURE_PURSE_MERGE``
- // over a `TALER_PurseMergeSignaturePS`.
- purse_sig: EddsaSignature;
-
- // Deposit fees that were charged to the purse.
- deposit_fees: Amount;
+ // CSR R1 value
+ r_pub_1: CsRPublic;
}
- .. ts:def:: ReserveWithdrawTransaction
- interface ReserveWithdrawTransaction {
- type: "WITHDRAW";
+Batch Withdraw
+~~~~~~~~~~~~~~
- // Amount withdrawn.
- amount: Amount;
+.. http:post:: /reserves/$RESERVE_PUB/batch-withdraw
- // Hash of the denomination public key of the coin.
- h_denom_pub: HashCode;
+ Withdraw multiple coins from the same reserve. Note that the client should
+ commit all of the request details, including the private key of the coins and
+ the blinding factors, to disk *before* issuing this request, so that it can
+ recover the information if necessary in case of transient failures, like
+ power outage, network outage, etc.
- // Hash of the blinded coin to be signed.
- h_coin_envelope: HashCode;
+ **Request:** The request body must be a `BatchWithdrawRequest` object.
- // Signature over a `TALER_WithdrawRequestPS`
- // with purpose ``TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW``
- // created with the reserve's private key.
- reserve_sig: EddsaSignature;
+ **Response:**
- // Fee that is charged for withdraw.
- withdraw_fee: Amount;
- }
+ :http:statuscode:`200 OK`:
+ The request was successful, and the response is a `BatchWithdrawResponse`.
+ Note that repeating exactly the same request will again yield the same
+ response, so if the network goes down during the transaction or before the
+ client can commit the coin signature to disk, the coin is not lost.
+ :http:statuscode:`403 Forbidden`:
+ A signature is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ A denomination key or the reserve are not known to the exchange. If the
+ denomination key is unknown, this suggests a bug in the wallet as the
+ wallet should have used current denomination keys from ``/keys``.
+ In this case, the response will be a `DenominationUnknownMessage`.
+ If the reserve is unknown, the wallet should not report a hard error yet, but
+ instead simply wait for up to a day, as the wire transaction might simply
+ not yet have completed and might be known to the exchange in the near future.
+ In this case, the wallet should repeat the exact same request later again
+ using exactly the same blinded coin.
+ :http:statuscode:`409 Conflict`:
+ One of the following reasons occured:
+ 1. The balance of the reserve is not sufficient to withdraw the coins of the
+ indicated denominations. The response is `WithdrawError` object.
- .. ts:def:: ReserveCreditTransaction
+ 2. The reserve has a birthday set and requires a request to ``/age-withdraw`` instead.
+ The response comes with a standard `ErrorDetail` response with error-code ``TALER_EC_EXCHANGE_RESERVES_AGE_RESTRICTION_REQUIRED`` and an additional field ``maximum_allowed_age`` for the maximum age (in years) that the client can commit to in the call to ``/age-withdraw``
+ :http:statuscode:`410 Gone`:
+ A requested denomination key is not yet or no longer valid.
+ It either before the validity start, past the expiration or was revoked.
+ The response is a `DenominationExpiredMessage`. Clients must evaluate the
+ error code provided to understand which of the cases this is and handle it
+ accordingly.
+ :http:statuscode:`451 Unavailable for Legal Reasons`:
+ This reserve has received funds from a purse or the amount withdrawn
+ exceeds another legal threshold and thus the reserve must
+ be upgraded to an account (with KYC) before the withdraw can
+ complete. Note that this response does NOT affirm that the
+ withdraw will ultimately complete with the requested amount.
+ The user should be redirected to the provided location to perform
+ the required KYC checks to open the account before withdrawing.
+ Afterwards, the request should be repeated.
+ The response will be an `KycNeededRedirect` object.
- interface ReserveCreditTransaction {
- type: "CREDIT";
+ Implementation note: internally, we need to
+ distinguish between upgrading the reserve to an
+ account (due to P2P payment) and identifying the
+ owner of the origin bank account (due to exceeding
+ the withdraw amount threshold), as we need to create
+ a different payto://-URI for the KYC check depending
+ on the case.
- // Amount deposited.
- amount: Amount;
- // Sender account ``payto://`` URL.
- sender_account_url: string;
+ **Details:**
- // Opaque identifier internal to the exchange that
- // uniquely identifies the wire transfer that credited the reserve.
- wire_reference: Integer;
+ .. ts:def:: BatchWithdrawRequest
- // Timestamp of the incoming wire transfer.
- timestamp: Timestamp;
- }
+ interface BatchWithdrawRequest {
+ // Array of requests for the individual coins to withdraw.
+ planchets: WithdrawRequest[];
+ }
- .. ts:def:: ReserveClosingTransaction
+ .. ts:def:: WithdrawRequest
- interface ReserveClosingTransaction {
- type: "CLOSING";
+ interface WithdrawRequest {
+ // Hash of a denomination public key, specifying the type of coin the client
+ // would like the exchange to create.
+ denom_pub_hash: HashCode;
- // Closing balance.
- amount: Amount;
+ // Coin's blinded public key, should be (blindly) signed by the exchange's
+ // denomination private key.
+ coin_ev: CoinEnvelope;
- // Closing fee charged by the exchange.
- closing_fee: Amount;
+ // Signature of `TALER_WithdrawRequestPS` created with
+ // the `reserves's private key <reserve-priv>`
+ // using purpose ``TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW``.
+ reserve_sig: EddsaSignature;
- // Wire transfer subject.
- wtid: string;
+ }
- // ``payto://`` URI of the wire account into which the funds were returned to.
- receiver_account_details: string;
- // This is a signature over a
- // struct `TALER_ReserveCloseConfirmationPS` with purpose
- // ``TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED``.
- exchange_sig: EddsaSignature;
+ .. ts:def:: BatchWithdrawResponse
- // Public key used to create 'exchange_sig'.
- exchange_pub: EddsaPublicKey;
+ interface BatchWithdrawResponse {
+ // Array of blinded signatures, in the same order as was
+ // given in the request.
+ ev_sigs: WithdrawResponse[];
- // Time when the reserve was closed.
- timestamp: Timestamp;
}
+ .. ts:def:: WithdrawResponse
- .. ts:def:: ReserveRecoupTransaction
+ interface WithdrawResponse {
+ // The blinded signature over the 'coin_ev', affirms the coin's
+ // validity after unblinding.
+ ev_sig: BlindedDenominationSignature;
- interface ReserveRecoupTransaction {
- type: "RECOUP";
+ }
- // Amount paid back.
- amount: Amount;
+ .. ts:def:: BlindedDenominationSignature
- // This is a signature over
- // a struct `TALER_RecoupConfirmationPS` with purpose
- // ``TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP``.
- exchange_sig: EddsaSignature;
+ type BlindedDenominationSignature =
+ | RsaBlindedDenominationSignature
+ | CSBlindedDenominationSignature;
- // Public key used to create 'exchange_sig'.
- exchange_pub: EddsaPublicKey;
+ .. ts:def:: RsaBlindedDenominationSignature
- // Time when the funds were paid back into the reserve.
- timestamp: Timestamp;
+ interface RsaBlindedDenominationSignature {
+ cipher: "RSA";
- // Public key of the coin that was paid back.
- coin_pub: CoinPublicKey;
+ // (blinded) RSA signature
+ blinded_rsa_signature: BlindedRsaSignature;
}
+ .. ts:def:: CSBlindedDenominationSignature
-.. http:post:: /reserves/$RESERVE_PUB/history
-
- Request information about the full history of
- a reserve or an account.
+ interface CSBlindedDenominationSignature {
+ type: "CS";
- **Request:**
+ // Signer chosen bit value, 0 or 1, used
+ // in Clause Blind Schnorr to make the
+ // ROS problem harder.
+ b: Integer;
- The request body must be a `ReserveHistoryRequest` object.
+ // Blinded scalar calculated from c_b.
+ s: Cs25519Scalar;
- **Response:**
+ }
- :http:statuscode:`200 OK`:
- The exchange responds with a `ReserveStatus` object; the reserve was known to the exchange.
- :http:statuscode:`401 Unauthorized`:
- The *Account-Request-Signature* is invalid.
- This response comes with a standard `ErrorDetail` response.
- :http:statuscode:`403 Forbidden`:
- The provided timestamp is not close to the current time.
- :http:statuscode:`404 Not found`:
- The reserve key does not belong to a reserve known to the exchange.
- :http:statuscode:`412 Precondition failed`:
- The balance in the reserve is insufficient to pay for the history request.
- This response comes with a standard `ErrorDetail` response.
+ .. ts:def:: KycNeededRedirect
- **Details:**
+ interface KycNeededRedirect {
- .. ts:def:: ReserveHistoryRequest
+ // Numeric `error code <error-codes>` unique to the condition.
+ // Should always be ``TALER_EC_EXCHANGE_GENERIC_KYC_REQUIRED``.
+ code: number;
- interface ReserveHistoryRequest {
- // Signature of type
- // ``TALER_SIGNATURE_RESERVE_HISTORY_REQUEST``
- // over a `TALER_ReserveHistoryRequestSignaturePS`.
- reserve_sig: EddsaSignature;
+ // Human-readable description of the error, i.e. "missing parameter", "commitment violation", ...
+ // Should give a human-readable hint about the error's nature. Optional, may change without notice!
+ hint?: string;
- // Time when the client made the request.
- // Timestamp must be reasonably close to the time of
- // the exchange, otherwise the exchange may reject
- // the request.
- request_timestamp: Timestamp;
- }
+ // Hash of the payto:// account URI that identifies
+ // the account which is being KYCed.
+ h_payto: PaytoHash;
+ // Legitimization target that the merchant should
+ // use to check for its KYC status using
+ // the ``/kyc-check/$REQUIREMENT_ROW/...`` endpoint.
+ requirement_row: Integer;
-.. http:post:: /reserves/$RESERVE_PUB/withdraw
+ }
- Withdraw a coin of the specified denomination. Note that the client should
- commit all of the request details, including the private key of the coin and
- the blinding factor, to disk *before* issuing this request, so that it can
- recover the information if necessary in case of transient failures, like
- power outage, network outage, etc.
+ .. ts:def:: WithdrawError
- **Request:** The request body must be a `WithdrawRequest` object.
+ interface WithdrawError {
+ // Text describing the error.
+ hint: string;
- **Response:**
+ // Detailed error code.
+ code: Integer;
- :http:statuscode:`200 OK`:
- The request was successful, and the response is a `WithdrawResponse`. Note that repeating exactly the same request
- will again yield the same response, so if the network goes down during the
- transaction or before the client can commit the coin signature to disk, the
- coin is not lost.
- :http:statuscode:`202 Accepted`:
- This reserve has received funds from a purse and must
- be upgraded to an account (with KYC) before the withdraw can
- complete. Note that this response does NOT affirm that the
- withdraw will ultimately complete with the requested amount.
- The user should be redirected to the provided location to perform
- the required KYC checks to open the account before withdrawing.
- Afterwards, the request should be repeated.
- The response will be an `AccountKycRedirect` object.
- :http:statuscode:`403 Forbidden`:
- The signature is invalid.
- :http:statuscode:`404 Not found`:
- The denomination key or the reserve are not known to the exchange. If the
- denomination key is unknown, this suggests a bug in the wallet as the
- wallet should have used current denomination keys from ``/keys``.
- In this case, the response will be a `DenominationUnknownMessage`.
- If the reserve is unknown, the wallet should not report a hard error yet, but
- instead simply wait for up to a day, as the wire transaction might simply
- not yet have completed and might be known to the exchange in the near future.
- In this case, the wallet should repeat the exact same request later again
- using exactly the same blinded coin.
- :http:statuscode:`409 Conflict`:
- The balance of the reserve is not sufficient to withdraw a coin of the indicated denomination.
- The response is `WithdrawError` object.
- :http:statuscode:`410 Gone`:
- The requested denomination key is not yet or no longer valid.
- It either before the validity start, past the expiration or was revoked. The response is a
- `DenominationExpiredMessage`. Clients must evaluate
- the error code provided to understand which of the
- cases this is and handle it accordingly.
+ // Amount left in the reserve.
+ balance: Amount;
- **Details:**
+ // History of the reserve's activity, in the same format
+ // as returned by ``/reserve/$RID/history``.
+ history: TransactionHistoryItem[]
+ }
.. ts:def:: DenominationExpiredMessage
@@ -1438,258 +1928,611 @@ exchange.
}
- .. ts:def:: WithdrawRequest
- interface WithdrawRequest {
- // Hash of a denomination public key (RSA), specifying the type of coin the client
- // would like the exchange to create.
- denom_pub_hash: HashCode;
- // Coin's blinded public key, should be (blindly) signed by the exchange's
- // denomination private key.
- coin_ev: CoinEnvelope;
- // Signature of `TALER_WithdrawRequestPS` created with
+Withdraw with Age Restriction
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If the reserve was marked with a maximum age group, the client has to perform a
+cut&choose protocol with the exchange. It first calls
+``/reserves/$RESERVE_PUB/age-withdraw`` and commits to ``n*kappa`` coins. On
+success, the exchange answers this request with an noreveal-index. The client
+then has to call ``/age-withdraw/$ACH/reveal`` to reveal all ``n*(kappa - 1)``
+coins along with their age commitments to proof that they were appropriate.
+If so, the exchange will blindly sign ``n`` undisclosed coins from the request.
+
+
+.. http:post:: /reserves/$RESERVE_PUB/age-withdraw
+
+ Withdraw multiple coins *with age restriction* from the same reserve.
+ Note that the client should commit all of the request details, including the
+ private key of the coins and the blinding factors, to disk *before* issuing
+ this request, so that it can recover the information if necessary in case of
+ transient failures, like power outage, network outage, etc.
+
+ **Request:** The request body must be a `AgeWithdrawRequest` object.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The request was successful, and the response is a `AgeWithdrawResponse`.
+ Note that repeating exactly the same request will again yield the same
+ response, so if the network goes down during the transaction or before the
+ client can commit the coin signature to disk, the coin is not lost.
+ :http:statuscode:`403 Forbidden`:
+ A signature is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`409 Conflict`:
+ One of two reasons occured:
+
+ 1. The balance of the reserve is not sufficient to withdraw the coins of the
+ given amount. The response is a `WithdrawError` object.
+
+ 2. The provided value for ``max_age`` is higher than the allowed value according to the reserve's birthday.
+ The response comes with a standard `ErrorDetail` response with error-code ``TALER_EC_EXCHANGE_AGE_WITHDRAW_MAXIMUM_AGE_TOO_LARGE`` and an additional field ``maximum_allowed_age`` for the maximum age (in years) that the client can commit to in a call to ``/age-withdraw``
+ :http:statuscode:`410 Gone`:
+ A requested denomination key is not yet or no longer valid.
+ It either before the validity start, past the expiration or was revoked.
+ The response is a `DenominationExpiredMessage`. Clients must evaluate the
+ error code provided to understand which of the cases this is and handle it
+ accordingly.
+ :http:statuscode:`451 Unavailable for Legal Reasons`:
+ This reserve has received funds from a purse or the amount withdrawn
+ exceeds another legal threshold and thus the reserve must
+ be upgraded to an account (with KYC) before the withdraw can
+ complete. Note that this response does NOT affirm that the
+ withdraw will ultimately complete with the requested amount.
+ The user should be redirected to the provided location to perform
+ the required KYC checks to open the account before withdrawing.
+ Afterwards, the request should be repeated.
+ The response will be an `KycNeededRedirect` object.
+
+ .. ts:def:: AgeWithdrawRequest
+
+ interface AgeWithdrawRequest {
+ // Array of ``n`` hash codes of denomination public keys to order.
+ // These denominations MUST support age restriction as defined in the
+ // output to /keys.
+ // The sum of all denomination's values and fees MUST be at most the
+ // balance of the reserve. The balance of the reserve will be
+ // immediatley reduced by that amount.
+ denoms_h: HashCode[];
+
+ // ``n`` arrays of ``kappa`` entries with blinded coin envelopes. Each
+ // (toplevel) entry represents ``kappa`` canditates for a particular
+ // coin. The exchange will respond with an index ``gamma``, which is
+ // the index that shall remain undisclosed during the reveal phase.
+ // The SHA512 hash $ACH over the blinded coin envelopes is the commitment
+ // that is later used as the key to the reveal-URL.
+ blinded_coins_evs: CoinEnvelope[][];
+
+ // The maximum age to commit to. MUST be the same as the maximum
+ // age in the reserve.
+ max_age: number;
+
+ // Signature of `TALER_AgeWithdrawRequestPS` created with
// the `reserves's private key <reserve-priv>`
- // using purpose ``TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW``.
+ // using purpose ``TALER_SIGNATURE_WALLET_RESERVE_AGE_WITHDRAW``.
reserve_sig: EddsaSignature;
-
}
- .. ts:def:: WithdrawResponse
+ .. ts:def:: AgeWithdrawResponse
- interface WithdrawResponse {
- // The blinded RSA signature over the 'coin_ev', affirms the coin's
- // validity after unblinding.
- ev_sig: BlindedRsaSignature;
+ interface AgeWithdrawResponse {
+ // index of the commitments that the client doesn't
+ // have to disclose
+ noreveal_index: Integer;
+ // Signature of `TALER_AgeWithdrawConfirmationPS` whereby
+ // the exchange confirms the ``noreveal_index``.
+ exchange_sig: EddsaSignature;
+
+ // `Public EdDSA key <sign-key-pub>` of the exchange that was used to
+ // generate the signature. Should match one of the exchange's signing
+ // keys from ``/keys``. Again given explicitly as the client might
+ // otherwise be confused by clock skew as to which signing key was used.
+ exchange_pub: EddsaPublicKey;
}
- .. ts:def:: WithdrawError
- interface WithdrawError {
- // Text describing the error.
- hint: string;
- // Detailed error code.
- code: Integer;
+.. http:post:: /age-withdraw/$ACH/reveal
- // Amount left in the reserve.
- balance: Amount;
+ The client has previously committed to multiple coins with age restriction
+ in a call to ``/reserve/$RESERVE_PUB/age-withdraw`` and got a
+ `AgeWithdrawResponse` from the exchange. By calling this
+ endpoint, the client has to reveal each coin and their ``kappa - 1``
+ age commitments, except for the age commitments with index
+ ``noreveal_index``. The hash of all commitments from the former withdraw
+ request is given as the ``$ACH`` value in the URL to this endpoint.
- // History of the reserve's activity, in the same format
- // as returned by ``/reserve/status``.
- history: TransactionHistoryItem[]
+
+ **Request:** The request body must be a `AgeWithdrawRevealRequest` object.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The request was successful, and the response is a `AgeWithdrawRevealResponse`.
+ Note that repeating exactly the same request will again yield the same
+ response, so if the network goes down during the transaction or before the
+ client can commit the coin signature to disk, the coin is not lost.
+ :http:statuscode:`404 Not found`:
+ The provided commitment $ACH is unknown.
+ :http:statuscode:`409 Conflict`:
+ The reveal operation failed and the response is an `WithdrawError` object.
+ The error codes indicate one of two cases:
+
+ 1. An age commitment for at least one of the coins did not fulfill the
+ required maximum age requirement of the corresponding reserve.
+ Error code:
+ ``TALER_EC_EXCHANGE_GENERIC_COIN_AGE_REQUIREMENT_FAILURE``.
+ 2. The computation of the hash of the commitment with provided input does
+ result in the value $ACH.
+ Error code:
+ ``TALER_EC_EXCHANGE_AGE_WITHDRAW_REVEAL_INVALID_HASH``
+
+
+ .. ts:def:: AgeWithdrawRevealRequest
+
+ interface AgeWithdrawRevealRequest {
+ // Array of ``n`` of ``(kappa - 1)`` disclosed coin master secrets, from
+ // which the coins' private key, blinding, nonce (for Clause-Schnorr) and
+ // age-restriction is calculated.
+ //
+ // Given each coin's private key and age commitment, the exchange will
+ // calculate each coin's blinded hash value und use all those (disclosed)
+ // blinded hashes together with the non-disclosed envelopes ``coin_evs``
+ // during the verification of the original age-withdraw-commitment.
+ disclosed_coin_secrets: AgeRestrictedCoinSecret[][];
}
-.. _delete-reserve:
+ .. ts:def:: AgeRestrictedCoinSecret
+
+ // The Master key material from which the coins' private key ``coin_priv``,
+ // blinding ``beta`` and nonce ``nonce`` (for Clause-Schnorr) itself are
+ // derived as usually in wallet-core. Given a coin's master key material,
+ // the age commitment for the coin MUST be derived from this private key as
+ // follows:
+ //
+ // Let m ∈ {1,...,M} be the maximum age group as defined in the reserve
+ // that the wallet can commit to.
+ //
+ // For age group $AG ∈ {1,...m}, set
+ // seed = HDKF(coin_secret, "age-commitment", $AG)
+ // p[$AG] = Edx25519_generate_private(seed)
+ // and calculate the corresponding Edx25519PublicKey as
+ // q[$AG] = Edx25519_public_from_private(p[$AG])
+ //
+ // For age groups $AG ∈ {m,...,M}, set
+ // f[$AG] = HDKF(coin_secret, "age-factor", $AG)
+ // and calculate the corresponding Edx25519PublicKey as
+ // q[$AG] = Edx25519_derive_public(`PublishedAgeRestrictionBaseKey`, f[$AG])
+ //
+ type AgeRestrictedCoinSecret = string;
+
+ .. ts:def:: PublishedAgeRestrictionBaseKey
+
+ // The value for ``PublishedAgeRestrictionBaseKey`` is a randomly chosen
+ // `Edx25519PublicKey` for which the private key is not known to the clients. It is
+ // used during the age-withdraw protocol so that clients can proof that they
+ // derived all public keys to age groups higher than their allowed maximum
+ // from this particular value.
+ const PublishedAgeRestrictionBaseKey =
+ new Edx25519PublicKey("CH0VKFDZ2GWRWHQBBGEK9MWV5YDQVJ0RXEE0KYT3NMB69F0R96TG");
+
+ .. ts:def:: AgeWithdrawRevealResponse
+
+ interface AgeWithdrawRevealResponse {
+ // List of the exchange's blinded RSA signatures on the new coins.
+ ev_sigs : BlindedDenominationSignature[];
+ }
-.. http:DELETE:: /reserves/$RESERVE_PUB
- Forcefully closes a reserve.
- The request header must contain an *Account-Request-Signature*.
+.. _reserve-history:
+
+---------------
+Reserve History
+---------------
+
+.. http:get:: /reserves/$RESERVE_PUB/history
+
+ Request information about the full history of
+ a reserve or an account.
**Request:**
- *Account-Request-Signature*: The client must provide Base-32 encoded EdDSA signature made with ``$ACCOUNT_PRIV``, affirming its authorization to delete the account. The purpose used MUST be ``TALER_SIGNATURE_RESERVE_CLOSE``.
+ The GET request should come with the following HTTP headers:
- :query force=BOOLEAN: *Optional.* If set to 'true' specified, the exchange
- will delete the account even if there is a balance remaining.
+ *If-None-Match*: The client MAY provide an ``If-None-Match`` header with an
+ Etag. In that case, the server MUST additionally respond with an ``304``
+ status code in case the reserve history matches the provided Etag.
+
+ *Taler-Reserve-History-Signature*: The client MUST provide Base-32 encoded
+ EdDSA signature over a TALER_SIGNATURE_RESERVE_HISTORY_REQUEST made with
+ the respective ``$RESERVE_PRIV``, affirming desire to download the current
+ reserve transaction history.
+
+ :query start=OFFSET: *Optional.* Only return reserve history entries with
+ offsets above the given OFFSET. Allows clients to not
+ retrieve history entries they already have.
**Response:**
:http:statuscode:`200 OK`:
- The operation succeeded, the exchange provides details
- about the account deletion.
- The response will include a `ReserveClosedResponse` object.
- :http:statuscode:`401 Unauthorized`:
- The *Account-Request-Signature* is invalid.
+ The exchange responds with a `ReserveHistory` object; the reserve was known to the exchange.
+ :http:statuscode:`204 No content`:
+ The reserve history is known, but at this point from the given starting point it is empty. Can only happen if OFFSET was positive.
+ :http:statuscode:`304 Not modified`:
+ The reserve history matches the one identified by the "If-none-match" HTTP header of the request.
+ :http:statuscode:`403 Forbidden`:
+ The *TALER_SIGNATURE_RESERVE_HISTORY_REQUEST* is invalid.
This response comes with a standard `ErrorDetail` response.
:http:statuscode:`404 Not found`:
- The account is unknown to the exchange.
- :http:statuscode:`409 Conflict`:
- The account is still has digital cash in it, the associated
- wire method is ``void`` and the *force* option was not provided.
- This response comes with a standard `ErrorDetail` response.
+ The reserve key does not belong to a reserve known to the exchange.
**Details:**
- .. ts:def:: ReserveClosedResponse
+ .. ts:def:: ReserveHistory
- interface ReserveClosedResponse {
+ interface ReserveHistory {
+ // Balance left in the reserve.
+ balance: Amount;
- // Final balance of the account.
- closing_amount: Amount;
+ // If set, gives the maximum age group that the client is required to set
+ // during withdrawal.
+ maximum_age_group: number;
- // Current time of the exchange, used as part of
- // what the exchange signs over.
- close_time: Timestamp;
+ // Transaction history for this reserve.
+ // May be partial (!).
+ history: TransactionHistoryItem[];
+ }
- // Hash of the wire account into which the remaining
- // balance will be transferred. Note: may be the
- // hash over ``payto://void/`, in which case the
- // balance is forfeit to the profit of the exchange.
+ Objects in the transaction history have the following format:
+
+ .. ts:def:: TransactionHistoryItem
+
+ // Union discriminated by the "type" field.
+ type TransactionHistoryItem =
+ | AccountSetupTransaction
+ | ReserveWithdrawTransaction
+ | ReserveAgeWithdrawTransaction
+ | ReserveCreditTransaction
+ | ReserveClosingTransaction
+ | ReserveOpenRequestTransaction
+ | ReserveCloseRequestTransaction
+ | PurseMergeTransaction;
+
+ .. ts:def:: AccountSetupTransaction
+
+ interface AccountSetupTransaction {
+ type: "SETUP";
+
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
+
+ // KYC fee agreed to by the reserve owner.
+ kyc_fee: Amount;
+
+ // Time when the KYC was triggered.
+ kyc_timestamp: Timestamp;
+
+ // Hash of the wire details of the account.
+ // Note that this hash is unsalted and potentially
+ // private (as it could be inverted), hence access
+ // to this endpoint must be authorized using the
+ // private key of the reserve.
h_wire: HashCode;
+ // Signature created with the reserve's private key.
+ // Must be of purpose ``TALER_SIGNATURE_ACCOUNT_SETUP_REQUEST`` over
+ // a ``TALER_AccountSetupRequestSignaturePS``.
+ reserve_sig: EddsaSignature;
+
+ }
+
+ .. ts:def:: ReserveWithdrawTransaction
+
+ interface ReserveWithdrawTransaction {
+ type: "WITHDRAW";
+
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
+
+ // Amount withdrawn.
+ amount: Amount;
+
+ // Hash of the denomination public key of the coin.
+ h_denom_pub: HashCode;
+
+ // Hash of the blinded coin to be signed.
+ h_coin_envelope: HashCode;
+
+ // Signature over a `TALER_WithdrawRequestPS`
+ // with purpose ``TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW``
+ // created with the reserve's private key.
+ reserve_sig: EddsaSignature;
+
+ // Fee that is charged for withdraw.
+ withdraw_fee: Amount;
+ }
+
+ .. ts:def:: ReserveAgeWithdrawTransaction
+
+ interface ReserveAgeWithdrawTransaction {
+ type: "AGEWITHDRAW";
+
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
+
+ // Total Amount withdrawn.
+ amount: Amount;
+
+ // Commitment of all ``n*kappa`` blinded coins.
+ h_commitment: HashCode;
+
+ // Signature over a `TALER_AgeWithdrawRequestPS`
+ // with purpose ``TALER_SIGNATURE_WALLET_RESERVE_AGE_WITHDRAW``
+ // created with the reserve's private key.
+ reserve_sig: EddsaSignature;
+
+ // Fee that is charged for withdraw.
+ withdraw_fee: Amount;
+ }
+
+
+ .. ts:def:: ReserveCreditTransaction
+
+ interface ReserveCreditTransaction {
+ type: "CREDIT";
+
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
+
+ // Amount deposited.
+ amount: Amount;
+
+ // Sender account ``payto://`` URL.
+ sender_account_url: string;
+
+ // Opaque identifier internal to the exchange that
+ // uniquely identifies the wire transfer that credited the reserve.
+ wire_reference: Integer;
+
+ // Timestamp of the incoming wire transfer.
+ timestamp: Timestamp;
+ }
+
+
+ .. ts:def:: ReserveClosingTransaction
+
+ interface ReserveClosingTransaction {
+ type: "CLOSING";
+
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
+
+ // Closing balance.
+ amount: Amount;
+
+ // Closing fee charged by the exchange.
+ closing_fee: Amount;
+
+ // Wire transfer subject.
+ wtid: Base32;
+
+ // ``payto://`` URI of the wire account into which the funds were returned to.
+ receiver_account_details: string;
+
// This is a signature over a
- // struct ``TALER_AccountDeleteConfirmationPS`` with purpose
+ // struct `TALER_ReserveCloseConfirmationPS` with purpose
// ``TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED``.
exchange_sig: EddsaSignature;
+ // Public key used to create 'exchange_sig'.
+ exchange_pub: EddsaPublicKey;
+
+ // Time when the reserve was closed.
+ timestamp: Timestamp;
}
+ .. ts:def:: ReserveOpenRequestTransaction
-.. _deposit-par:
+ interface ReserveOpenRequestTransaction {
+ type: "OPEN";
--------
-Deposit
--------
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
-Deposit operations are requested by a merchant during a transaction. For the
-deposit operation, the merchant has to obtain the deposit permission for a coin
-from their customer who owns the coin. When depositing a coin, the merchant is
-credited an amount specified in the deposit permission, possibly a fraction of
-the total coin's value, minus the deposit fee as specified by the coin's
-denomination.
+ // Open fee paid from the reserve.
+ open_fee: Amount;
-.. _deposit:
+ // This is a signature over
+ // a struct `TALER_ReserveOpenPS` with purpose
+ // ``TALER_SIGNATURE_WALLET_RESERVE_OPEN``.
+ reserve_sig: EddsaSignature;
-.. http:POST:: /coins/$COIN_PUB/deposit
+ // Timestamp of the open request.
+ request_timestamp: Timestamp;
- Deposit the given coin and ask the exchange to transfer the given :ref:`amount`
- to the merchant's bank account. This API is used by the merchant to redeem
- the digital coins.
+ // Requested expiration.
+ requested_expiration: Timestamp;
- The base URL for ``/coins/``-requests may differ from the main base URL of the
- exchange. The exchange MUST return a 307 or 308 redirection to the correct
- base URL if this is the case.
+ // Requested number of free open purses.
+ requested_min_purses: Integer;
- **Request:**
+ }
- The request body must be a `DepositRequest` object.
+ .. ts:def:: ReserveCloseRequestTransaction
- **Response:**
+ interface ReserveCloseRequestTransaction {
+ type: "CLOSE";
- :http:statuscode:`200 OK`:
- The operation succeeded, the exchange confirms that no double-spending took
- place. The response will include a `DepositSuccess` object.
- :http:statuscode:`401 Unauthorized`:
- One of the signatures is invalid.
- :http:statuscode:`404 Not found`:
- Either the denomination key is not recognized (expired or invalid),
- or the wire type is not recognized.
- If the denomination key is unknown, the response will be
- a `DenominationUnknownMessage`.
- :http:statuscode:`409 Conflict`:
- The deposit operation has either failed because the coin has insufficient
- residual value, or because the same public key of the coin has been
- previously used with a different denomination. Which case it is
- can be decided by looking at the error code
- (``TALER_EC_EXCHANGE_DEPOSIT_INSUFFICIENT_FUNDS`` or ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY``).
- The fields of the response are the same in both cases.
- The request should not be repeated again with this coin.
- In this case, the response is a `DepositDoubleSpendError`.
- :http:statuscode:`410 Gone`:
- The requested denomination key is not yet or no longer valid.
- It either before the validity start, past the expiration or was revoked. The response is a
- `DenominationExpiredMessage`. Clients must evaluate
- the error code provided to understand which of the
- cases this is and handle it accordingly.
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
- **Details:**
+ // This is a signature over
+ // a struct `TALER_ReserveClosePS` with purpose
+ // ``TALER_SIGNATURE_WALLET_RESERVE_CLOSE``.
+ reserve_sig: EddsaSignature;
- .. ts:def:: DepositRequest
+ // Target account ``payto://``, optional.
+ h_payto?: PaytoHash;
- interface DepositRequest {
- // Amount to be deposited, can be a fraction of the
- // coin's total value.
- contribution: Amount;
+ // Timestamp of the close request.
+ request_timestamp: Timestamp;
+ }
- // The merchant's account details.
- // The salt is used to hide the ``payto_uri`` from customers
- // that learn the ``h_wire`` of the merchant.
- wire: {
- payto_uri: string;
- salt: HashCode;
- };
-
- // SHA-512 hash of the merchant's payment details from ``wire``. Although
- // strictly speaking redundant, this helps detect inconsistencies.
- h_wire: HashCode;
+ .. ts:def:: ReserveCreditTransaction
- // SHA-512 hash of the contract of the merchant with the customer. Further
- // details are never disclosed to the exchange.
- h_contract_terms: HashCode;
+ interface ReserveCreditTransaction {
+ type: "CREDIT";
- // Hash of denomination RSA key with which the coin is signed.
- denom_pub_hash: HashCode;
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
- // Exchange's unblinded RSA signature of the coin.
- ub_sig: RsaSignature;
+ // Amount deposited.
+ amount: Amount;
- // Timestamp when the contract was finalized.
+ // Sender account ``payto://`` URL.
+ sender_account_url: string;
+
+ // Opaque identifier internal to the exchange that
+ // uniquely identifies the wire transfer that credited the reserve.
+ wire_reference: Integer;
+
+ // Timestamp of the incoming wire transfer.
timestamp: Timestamp;
+ }
- // Indicative time by which the exchange undertakes to transfer the funds to
- // the merchant, in case of successful payment.
- wire_transfer_deadline: Timestamp;
+ .. ts:def:: PurseMergeTransaction
- // EdDSA `public key of the merchant <merchant-pub>`, so that the client can identify the
- // merchant for refund requests.
- merchant_pub: EddsaPublicKey;
+ interface PurseMergeTransaction {
+ type: "MERGE";
- // Date until which the merchant can issue a refund to the customer via the
- // exchange, to be omitted if refunds are not allowed.
- refund_deadline?: Timestamp;
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
- // Signature over `TALER_DepositRequestPS`, made by the customer with the
- // `coin's private key <coin-priv>`.
- coin_sig: EddsaSignature;
- }
+ // SHA-512 hash of the contact of the purse.
+ h_contract_terms: HashCode;
- The deposit operation succeeds if the coin is valid for making a deposit and
- has enough residual value that has not already been deposited or melted.
+ // EdDSA public key used to approve merges of this purse.
+ merge_pub: EddsaPublicKey;
- .. ts:def:: DepositSuccess
+ // Minimum age required for all coins deposited into the purse.
+ min_age: Integer;
- interface DepositSuccess {
- // Optional base URL of the exchange for looking up wire transfers
- // associated with this transaction. If not given,
- // the base URL is the same as the one used for this request.
- // Can be used if the base URL for ``/transactions/`` differs from that
- // for ``/coins/``, i.e. for load balancing. Clients SHOULD
- // respect the ``transaction_base_url`` if provided. Any HTTP server
- // belonging to an exchange MUST generate a 307 or 308 redirection
- // to the correct base URL should a client uses the wrong base
- // URL, or if the base URL has changed since the deposit.
- transaction_base_url?: string;
+ // Number that identifies who created the purse
+ // and how it was paid for.
+ flags: Integer;
- // Timestamp when the deposit was received by the exchange.
- exchange_timestamp: Timestamp;
+ // Purse public key.
+ purse_pub: EddsaPublicKey;
- // The EdDSA signature of `TALER_DepositConfirmationPS` using a current
- // `signing key of the exchange <sign-key-priv>` affirming the successful
- // deposit and that the exchange will transfer the funds after the refund
- // deadline, or as soon as possible if the refund deadline is zero.
- exchange_sig: EddsaSignature;
+ // EdDSA signature of the account/reserve affirming the merge
+ // over a `TALER_AccountMergeSignaturePS`.
+ // Must be of purpose ``TALER_SIGNATURE_ACCOUNT_MERGE``
+ reserve_sig: EddsaSignature;
- // `Public EdDSA key of the exchange <sign-key-pub>` that was used to
- // generate the signature.
- // Should match one of the exchange's signing keys from ``/keys``. It is given
- // explicitly as the client might otherwise be confused by clock skew as to
- // which signing key was used.
- exchange_pub: EddsaPublicKey;
+ // Client-side timestamp of when the merge request was made.
+ merge_timestamp: Timestamp;
+
+ // Indicative time by which the purse should expire
+ // if it has not been merged into an account. At this
+ // point, all of the deposits made should be
+ // auto-refunded.
+ purse_expiration: Timestamp;
+
+ // Purse fee the reserve owner paid for the purse creation.
+ purse_fee: Amount;
+
+ // Total amount merged into the reserve.
+ // (excludes fees).
+ amount: Amount;
+
+ // True if the purse was actually merged.
+ // If false, only the purse_fee has an impact
+ // on the reserve balance!
+ merged: boolean;
}
- .. ts:def:: DepositDoubleSpendError
- interface DepositDoubleSpendError {
- // The string constant "insufficient funds".
- hint: string;
+.. _coin-history:
- // Transaction history for the coin that is
- // being double-spended.
+------------
+Coin History
+------------
+
+.. http:get:: /coins/$COIN_PUB/history
+
+ Obtain the transaction history of a coin. Used only in special cases, like
+ when the exchange claims a double-spending error and the wallet does not
+ believe it. Usually, the wallet knows the transaction history of each coin
+ and thus has no need to inquire.
+
+ **Request:**
+
+ The GET request should come with the following HTTP headers:
+
+ *If-None-Match*: The client MAY provide an ``If-None-Match`` header with an
+ Etag. In that case, the server MUST additionally respond with an ``304``
+ status code in case the coin history matches the provided Etag.
+
+ *Taler-Coin-History-Signature*: The client MUST provide Base-32 encoded
+ EdDSA signature over a TALER_SIGNATURE_COIN_HISTORY_REQUEST made with
+ the respective ``$RESERVE_PRIV``, affirming desire to download the current
+ coin transaction history.
+
+ :query start=OFFSET: *Optional.* Only return coin history entries with
+ offsets above the given OFFSET. Allows clients to not
+ retrieve history entries they already have.
+
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The operation succeeded, the exchange confirms that no double-spending took
+ place. The response will include a `CoinHistoryResponse` object.
+ :http:statuscode:`204 No content`:
+ The reserve history is known, but at this point from the given starting point it is empty. Can only happen if OFFSET was positive.
+ :http:statuscode:`304 Not modified`:
+ The coin history has not changed since the previous query (detected via Etag
+ in "If-none-match" header).
+ :http:statuscode:`403 Forbidden`:
+ The *TALER_SIGNATURE_COIN_HISTORY_REQUEST* is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ The coin public key is not (yet) known to the exchange.
+
+ .. ts:def:: CoinHistoryResponse
+
+ interface CoinHistoryResponse {
+ // Current balance of the coin.
+ balance: Amount;
+
+ // Hash of the coin's denomination.
+ h_denom_pub: HashCode;
+
+ // Transaction history for the coin.
history: CoinSpendHistoryItem[];
}
@@ -1704,14 +2547,19 @@ denomination.
| CoinOldCoinRecoupTransaction
| CoinRecoupRefreshTransaction
| CoinPurseDepositTransaction
- | CoinPurseRefundTransaction;
-
+ | CoinPurseRefundTransaction
+ | CoinReserveOpenDepositTransaction;
.. ts:def:: CoinDepositTransaction
interface CoinDepositTransaction {
type: "DEPOSIT";
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
+
// The total amount of the coin's value absorbed (or restored in the
// case of a refund) by this transaction.
// The amount given includes
@@ -1755,6 +2603,11 @@ denomination.
interface CoinMeltTransaction {
type: "MELT";
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
+
// The total amount of the coin's value absorbed by this transaction.
// Note that for melt this means the amount given includes
// the melt fee. The current coin value can thus be computed by
@@ -1784,6 +2637,11 @@ denomination.
interface CoinRefundTransaction {
type: "REFUND";
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
+
// The total amount of the coin's value restored
// by this transaction.
// The amount given excludes the transaction fee.
@@ -1814,6 +2672,11 @@ denomination.
interface CoinRecoupTransaction {
type: "RECOUP";
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
+
// The total amount of the coin's value absorbed
// by this transaction.
// The current coin value can thus be computed by
@@ -1855,6 +2718,11 @@ denomination.
interface CoinOldCoinRecoupTransaction {
type: "OLD-COIN-RECOUP";
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
+
// The total amount of the coin's value restored
// by this transaction.
// The current coin value can thus be computed by
@@ -1879,6 +2747,11 @@ denomination.
interface CoinRecoupRefreshTransaction {
type: "RECOUP-REFRESH";
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
+
// The total amount of the coin's value absorbed
// by this transaction.
// The current coin value can thus be computed by
@@ -1910,16 +2783,21 @@ denomination.
exchange_pub: EddsaPublicKey;
// Blinding factor of the revoked new coin.
- new_coin_blinding_secret: RsaBlindingKeySecret;
+ new_coin_blinding_secret: DenominationBlindingKeySecret;
// Blinded public key of the revoked new coin.
- new_coin_ev: RsaBlindingKeySecret;
+ new_coin_ev: DenominationBlindingKeySecret;
}
.. ts:def:: CoinPurseDepositTransaction
interface CoinPurseDepositTransaction {
- type: "PURSE_DEPOSIT";
+ type: "PURSE-DEPOSIT";
+
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
// The total amount of the coin's value absorbed
// by this transaction.
@@ -1953,7 +2831,12 @@ denomination.
.. ts:def:: CoinPurseRefundTransaction
interface CoinPurseRefundTransaction {
- type: "PURSE_REFUND";
+ type: "PURSE-REFUND";
+
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
// The total amount of the coin's value restored
// by this transaction.
@@ -1966,11 +2849,6 @@ denomination.
// fee will be waived.
refund_fee: Amount;
- // Share of the purse fee charged to this coin.
- // The sum of all purse fee shares will match the
- // total purse fee.
- purse_fee_share: Amount;
-
// Public key of the purse that expired.
purse_pub: EddsaPublicKey;
@@ -1979,11 +2857,391 @@ denomination.
// of purpose ``TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_REFUND``.
exchange_sig: EddsaSignature;
- // Public key used to sign 'exchange_sig'.
+ // Public key used to sign 'exchange_sig'.
exchange_pub: EddsaPublicKey;
}
+ .. ts:def:: CoinReserveOpenDepositTransaction
+
+ interface CoinReserveOpenDepositTransaction {
+ type: "RESERVE-OPEN-DEPOSIT";
+
+ // Offset of this entry in the reserve history.
+ // Useful to request incremental histories via
+ // the "start" query parameter.
+ history_offset: Integer;
+
+ // The total amount of the coin's value absorbed
+ // by this transaction.
+ // Note that this means the amount given includes
+ // the deposit fee.
+ coin_contribution: Amount;
+
+ // Signature of the reserve open operation being paid for.
+ reserve_sig: EddsaSignature;
+
+ // Signature by the coin over a
+ // `TALER_ReserveOpenDepositSignaturePS` of
+ // purpose ``TALER_SIGNATURE_RESERVE_OPEN_DEPOSIT``.
+ coin_sig: EddsaSignature;
+
+ }
+
+
+.. _deposit-par:
+
+-------
+Deposit
+-------
+
+Deposit operations are requested f.e. by a merchant during a transaction or a
+bidder during an auction.
+
+For the deposit operation during purchase, the merchant has to obtain the
+deposit permission for a coin from their customer who owns the coin. When
+depositing a coin, the merchant is credited an amount specified in the deposit
+permission, possibly a fraction of the total coin's value, minus the deposit
+fee as specified by the coin's denomination.
+
+For auctions, a bidder performs an deposit operation and provides all relevant
+information for the auction policy (such as timeout and public key as bidder)
+and can use the ``exchange_sig`` field from the `DepositSuccess` message as a
+proof to the seller for the escrow of sufficient fund.
+
+
+.. _deposit:
+
+.. http:post:: /batch-deposit
+
+ Deposit multiple coins and ask the exchange to transfer the given :ref:`amount`
+ into the merchant's bank account. This API is used by the merchant to redeem
+ the digital coins.
+
+ **Request:**
+
+ The request body must be a `BatchDepositRequest` object.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The operation succeeded, the exchange confirms that no double-spending took
+ place. The response will include a `DepositSuccess` object.
+ :http:statuscode:`403 Forbidden`:
+ One of the signatures is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ Either one of the denomination keys is not recognized (expired or invalid),
+ or the wire type is not recognized.
+ If a denomination key is unknown, the response will be
+ a `DenominationUnknownMessage`.
+ :http:statuscode:`409 Conflict`:
+ The deposit operation has either failed because a coin has insufficient
+ residual value, or because the same public key of a coin has been
+ previously used with a different denomination.
+ Which case it is can be decided by looking at the error code:
+
+ 1. ``TALER_EC_EXCHANGE_DEPOSIT_CONFLICTING_CONTRACT`` (same coin used in different ways),
+ 2. ``TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS`` (balance insufficient),
+ 3. ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY`` (same coin public key, but different denomination).
+ 4. ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_AGE_HASH`` (same coin public key, but different age commitment).
+
+ The request should not be repeated again with this coin. Instead, the client
+ can get from the exchange via the ``/coin/$COIN_PUB/history`` endpoint the record
+ of the transactions known for this coin's public key.
+ :http:statuscode:`410 Gone`:
+ The requested denomination key is not yet or no longer valid.
+ It either before the validity start, past the expiration or was revoked. The response is a
+ `DenominationExpiredMessage`. Clients must evaluate
+ the error code provided to understand which of the
+ cases this is and handle it accordingly.
+
+ **Details:**
+
+ .. ts:def:: BatchDepositRequest
+
+ interface BatchDepositRequest {
+
+ // The merchant's account details.
+ merchant_payto_uri: string;
+
+ // The salt is used to hide the ``payto_uri`` from customers
+ // when computing the ``h_wire`` of the merchant.
+ wire_salt: WireSalt;
+
+ // SHA-512 hash of the contract of the merchant with the customer. Further
+ // details are never disclosed to the exchange.
+ h_contract_terms: HashCode;
+
+ // The list of coins that are going to be deposited with this Request.
+ coins: BatchDepositRequestCoin[];
+
+ // Timestamp when the contract was finalized.
+ timestamp: Timestamp;
+
+ // Indicative time by which the exchange undertakes to transfer the funds to
+ // the merchant, in case of successful payment. A wire transfer deadline of 'never'
+ // is not allowed.
+ wire_transfer_deadline: Timestamp;
+
+ // EdDSA `public key of the merchant <merchant-pub>`, so that the client can identify the
+ // merchant for refund requests.
+ merchant_pub: EddsaPublicKey;
+
+ // Date until which the merchant can issue a refund to the customer via the
+ // exchange, to be omitted if refunds are not allowed.
+ //
+ // THIS FIELD WILL BE DEPRICATED, once the refund mechanism becomes a
+ // policy via extension.
+ refund_deadline?: Timestamp;
+
+ // CAVEAT: THIS IS WORK IN PROGRESS
+ // (Optional) policy for the batch-deposit.
+ // This might be a refund, auction or escrow policy.
+ policy?: DepositPolicy;
+ }
+
+ .. ts:def:: BatchDepositRequestCoin
+
+ interface BatchDepositRequestCoin {
+ // EdDSA public key of the coin being deposited.
+ coin_pub: EddsaPublicKey;
+
+ // Hash of denomination RSA key with which the coin is signed.
+ denom_pub_hash: HashCode;
+
+ // Exchange's unblinded RSA signature of the coin.
+ ub_sig: DenominationSignature;
+
+ // Amount to be deposited, can be a fraction of the
+ // coin's total value.
+ contribution: Amount;
+
+ // Signature over `TALER_DepositRequestPS`, made by the customer with the
+ // `coin's private key <coin-priv>`.
+ coin_sig: EddsaSignature;
+ }
+
+ .. ts:def:: DenominationSignature
+
+ type DenominationSignature =
+ | RsaDenominationSignature
+ | CSDenominationSignature;
+
+ .. ts:def:: RsaDenominationSignature
+
+ interface RsaDenominationSignature {
+ cipher: "RSA";
+
+ // RSA signature
+ rsa_signature: RsaSignature;
+ }
+
+ .. ts:def:: CSDenominationSignature
+
+ interface CSDenominationSignature {
+ type: "CS";
+
+ // R value component of the signature.
+ cs_signature_r: Cs25519Point;
+
+ // s value component of the signature.
+ cs_signature_s: Cs25519Scalar:
+
+ }
+
+ .. ts:def:: DepositPolicy
+
+ type DepositPolicy =
+ | PolicyMerchantRefund
+ | PolicyBrandtVickreyAuction
+ | PolicyEscrowedPayment;
+
+ .. ts:def:: PolicyMerchantRefund
+
+ // CAVEAT: THIS IS STILL WORK IN PROGRESS.
+ // This policy is optional and might not be supported by the exchange.
+ // If it does, the exchange MUST show support for this policy in the
+ // ``extensions`` field in the response to ``/keys``.
+ interface PolicyMerchantRefund {
+ type: "merchant_refund";
+
+ // EdDSA `public key of the merchant <merchant-pub>`, so that the client
+ // can identify the merchant for refund requests.
+ merchant_pub: EddsaPublicKey;
+
+ // Date until which the merchant can issue a refund to the customer via
+ // the ``/extensions/policy_refund``-endpoint of the exchange.
+ deadline: Timestamp;
+ }
+
+ .. ts:def:: PolicyBrandtVickreyAuction
+
+ // CAVEAT: THIS IS STILL WORK IN PROGRESS.
+ // This policy is optional and might not be supported by the exchange.
+ // If it does, the exchange MUST show support for this policy in the
+ // ``extensions`` field in the response to ``/keys``.
+ interface PolicyBrandtVickreyAuction {
+ type: "brandt_vickrey_auction";
+
+ // Public key of this bidder.
+ //
+ // The bidder uses this key to sign the auction information and
+ // the messages it sends to the seller during the auction.
+ bidder_pub: EddsaPublicKey;
+
+ // Hash of the auction terms
+ //
+ // The hash should be taken over a normalized JSON object of type
+ // `BrandtVickreyAuction`.
+ h_auction: HashCode;
+
+ // The amount that this bidder commits to for this auction
+ //
+ // This amount can be larger than the contribution of a single coin.
+ // The bidder can increase funding of this auction policy by using
+ // sufficiently many coins during the deposit operation (single or batch)
+ // with the same policy.
+ commitment: Amount;
+
+ // Date until the auction must have been successfully executed and
+ // a valid transcript provided to the
+ // ``/extensions/policy_brandt_vickrey_auction``-endpoint of the
+ // exchange.
+ //
+ // [If the auction has not been executed by then] OR [has been executed
+ // before then, but this bidder did not win], the coin's value doesn't
+ // change and the owner can refresh the coin.
+ //
+ // If this bidder won the auction, the winning price/amount from the
+ // outcome will be substracted from the coin and transfered to the
+ // merchant's ``payout_uri`` from the deposit request (minus a potential
+ // auction fee). For any remaining value, the bidder can refresh the
+ // coin to retrieve change.
+ deadline: Timestamp;
+ }
+
+ .. ts:def:: BrandtVickreyAuction
+
+ // CAVEAT: THIS IS STILL WORK IN PROGRESS.
+ // This structure defines an auction of Brandt-Vickory kind.
+ // It is used for the `PolicyBrandtVickreyAuction`.
+ interface BrandtVickreyAuction {
+ // Start date of the auction
+ time_start: Timestamp;
+
+ // Maximum duration per round. There are four rounds in an auction of
+ // Brandt-Vickrey kind.
+ time_round: RelativeTime;
+
+ // This integer m refers to the (m+1)-type of the Brandt-Vickrey-auction.
+ // - Type 0 refers to an auction with one highest-price winner,
+ // - Type 1 refers to an auction with one winner, paying the second
+ // highest price,
+ // - Type 2 refers to an auction with two winners, paying
+ // the third-highest price,
+ // - etc.
+ auction_type: number;
+
+ // The vector of prices for the Brandt-Vickrey auction. The values MUST
+ // be in strictly increasing order.
+ prices: Amount[];
+
+ // The type of outcome of the auction.
+ // In case the auction is declared public, each bidder can calculate the
+ // winning price. This field is not relevant for the replay of a
+ // transcript, as the transcript must be provided by the seller who sees
+ // the winner(s) and winning price of the auction.
+ outcome_public: boolean;
+
+ // The public key of the seller.
+ pubkey: EddsaPublicKey;
+
+ // The seller's account details.
+ payto_uri: string;
+ }
+
+
+ .. ts:def:: PolicyEscrowedPayment
+
+ // CAVEAT: THIS IS STILL WORK IN PROGRESS
+ // This policy is optional and might not be supported by the exchange.
+ // If it does, the exchange MUST show support for this policy in the
+ // ``extensions`` field in the response to ``/keys``.
+ interface PolicyEscrowedPayment {
+ type: "escrowed_payment";
+
+ // Public key of this trustor, the owner of the coins.
+ //
+ // To claim the deposit, the merchant must provide the valid signature
+ // of the ``h_contract_terms`` field from the deposit, signed by _this_
+ // key, to the ``/extensions/policy_escrow``-endpoint of the exchange,
+ // after the date specified in ``not_before`` and before the date
+ // specified in ``not_after``.
+ trustor_pub: EddsaPublicKey;
+
+ // Latest date by which the deposit must be claimed. If the deposit
+ // has not been claimed by that date, the deposited coins can be
+ // refreshed by the (still) owner.
+ deadline: Timestamp;
+ }
+
+ The deposit operation succeeds if the coin is valid for making a deposit and
+ has enough residual value that has not already been deposited or melted.
+
+ .. ts:def:: DepositSuccess
+
+ interface DepositSuccess {
+ // Optional base URL of the exchange for looking up wire transfers
+ // associated with this transaction. If not given,
+ // the base URL is the same as the one used for this request.
+ // Can be used if the base URL for ``/transactions/`` differs from that
+ // for ``/coins/``, i.e. for load balancing. Clients SHOULD
+ // respect the ``transaction_base_url`` if provided. Any HTTP server
+ // belonging to an exchange MUST generate a 307 or 308 redirection
+ // to the correct base URL should a client uses the wrong base
+ // URL, or if the base URL has changed since the deposit.
+ transaction_base_url?: string;
+
+ // Timestamp when the deposit was received by the exchange.
+ exchange_timestamp: Timestamp;
+
+ // `Public EdDSA key of the exchange <sign-key-pub>` that was used to
+ // generate the signature.
+ // Should match one of the exchange's signing keys from ``/keys``. It is given
+ // explicitly as the client might otherwise be confused by clock skew as to
+ // which signing key was used.
+ exchange_pub: EddsaPublicKey;
+
+ // Deposit confirmation signature from the exchange.
+ // The EdDSA signature of `TALER_DepositConfirmationPS` using a current
+ // `signing key of the exchange <sign-key-priv>` affirming the successful
+ // deposit and that the exchange will transfer the funds after the refund
+ // deadline, or as soon as possible if the refund deadline is zero.
+ exchange_sig: EddsaSignature;
+ }
+
+ .. ts:def:: DepositDoubleSpendError
+
+ interface DepositDoubleSpendError {
+
+ // Must be TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS
+ code: Integer;
+
+ // A string explaining that the user tried to
+ // double-spend.
+ hint: string;
+
+ // EdDSA public key of a coin being double-spent.
+ coin_pub: EddsaPublicKey;
+
+ // Transaction history for the coin that is
+ // being double-spended.
+ // DEPRECATED! Will be removed soon. Use
+ // GET /coins/$COIN_PUB to get the history!
+ history: CoinSpendHistoryItem[];
+ }
+
----------
Refreshing
@@ -2001,6 +3259,73 @@ using the ``/refresh/link`` request. While ``/refresh/link`` must be implemente
the exchange to achieve taxability, wallets do not really ever need that part of
the API during normal operation.
+
+.. http:post:: /csr-melt
+
+ Obtain exchange-side input values in preparation for a
+ melt step for certain denomination cipher types,
+ specifically at this point for Clause-Schnorr blind
+ signatures.
+
+ **Request:** The request body must be a `MeltPrepareRequest` object.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The request was successful, and the response is a `MeltPrepareResponse`. Note that repeating exactly the same request
+ will again yield the same response (assuming none of the denomination is expired).
+ :http:statuscode:`404 Not found`:
+ A denomination key is not known to the exchange.
+ :http:statuscode:`410 Gone`:
+ A requested denomination key is not yet or no longer valid.
+ It either before the validity start, past the expiration or was revoked. The response is a
+ `DenominationExpiredMessage`. Clients must evaluate
+ the error code provided to understand which of the
+ cases this is and handle it accordingly.
+
+ **Details:**
+
+ .. ts:def:: MeltPrepareRequest
+
+ interface WithdrawPrepareRequest {
+
+ // Master seed for the Clause-schnorr R-value
+ // creation.
+ // Must not have been used in any prior request.
+ rms: RefreshMasterSeed;
+
+ // Array of denominations and coin offsets for
+ // each of the fresh coins with a CS-cipher
+ // denomination.
+ nks: MeltPrepareDenomNonce[];
+
+ }
+
+ .. ts:def:: MeltPrepareDenomNonce
+
+ interface MeltPrepareDenomNonce {
+
+ // Offset of this coin in the list of
+ // fresh coins. May not match the array offset
+ // as the fresh coins may include non-CS
+ // denominations as well.
+ coin_offset: Integer;
+
+ // Hash of the public key of the denomination the
+ // request relates to. Must be a CS denomination type.
+ denom_pub_hash: HashCode;
+ }
+
+
+ .. ts:def:: MeltPrepareResponse
+
+ interface MeltPrepareResponse {
+ // Responses for each request, in the same
+ // order that was used in the request.
+ ewvs: ExchangeWithdrawValue[];
+ }
+
+
.. _refresh:
.. http:post:: /coins/$COIN_PUB/melt
@@ -2028,7 +3353,8 @@ the API during normal operation.
residual value, or because the same public key of the coin has been
previously used with a different denomination. Which case it is
can be decided by looking at the error code
- (``TALER_EC_EXCHANGE_MELT_INSUFFICIENT_FUNDS`` or ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY``).
+ (``TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS`` or
+ ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY``).
The response is `MeltForbiddenResponse` in both cases.
:http:statuscode:`410 Gone`:
The requested denomination key is not yet or no longer valid.
@@ -2048,7 +3374,7 @@ the API during normal operation.
denom_pub_hash: HashCode;
// Signature over the `coin public key <eddsa-coin-pub>` by the denomination.
- denom_sig: RsaSignature;
+ denom_sig: DenominationSignature;
// Signature by the `coin <coin-priv>` over the melt commitment.
confirm_sig: EddsaSignature;
@@ -2059,8 +3385,19 @@ the API during normal operation.
// Melt commitment. Hash over the various coins to be withdrawn.
// See also ``TALER_refresh_get_commitment()``.
- rc: TALER_RefreshCommitmentP;
-
+ rc: HashCode;
+
+ // Master seed for the Clause-schnorr R-value
+ // creation. Must match the /csr-melt request.
+ // Must not have been used in any prior melt request.
+ // Must be present if one of the fresh coin's
+ // denominations is of type Clause-Schnorr.
+ rms?: RefreshMasterSeed;
+
+ // IFF the denomination has age restriction support, the client MUST
+ // provide the SHA256 hash of the age commitment of the coin.
+ // MUST be omitted otherwise.
+ age_commitment_hash?: AgeCommitmentHash;
}
For details about the HKDF used to derive the new coin private keys and
@@ -2111,18 +3448,6 @@ the API during normal operation.
// Detailed error code.
code: Integer;
- // Public key of a melted coin that had insufficient funds.
- coin_pub: EddsaPublicKey;
-
- // Original total value of the coin.
- original_value: Amount;
-
- // Remaining value of the coin.
- residual_value: Amount;
-
- // Amount of the coin's value that was to be melted.
- requested_value: Amount;
-
// The transaction list of the respective coin that failed to have sufficient funds left.
// Note that only the transaction history for one bogus coin is given,
// even if multiple coins would have failed the check.
@@ -2195,15 +3520,19 @@ the API during normal operation.
// Signs over a `TALER_CoinLinkSignaturePS`.
link_sigs: EddsaSignature[];
+ // IFF the corresponding denomination has support for age restriction,
+ // the client MUST provide the original age commitment, i. e. the
+ // vector of public keys.
+ // The size of the vector MUST be the number of age groups as defined by the
+ // Exchange in the field ``.age_groups`` of the extension ``age_restriction``.
+ old_age_commitment?: Edx25519PublicKey[];
+
}
.. ts:def:: RevealResponse
- interface RevealResponse {
- // List of the exchange's blinded RSA signatures on the new coins.
- ev_sigs : Array<{ ev_sig: BlindedRsaSignature }>;
- }
+ type RevealResponse = BatchWithdrawResponse;
.. ts:def:: RevealConflictResponse
@@ -2230,9 +3559,7 @@ the API during normal operation.
**Response:**
:http:statuscode:`200 OK`:
- All commitments were revealed successfully. The exchange returns an array,
- typically consisting of only one element, in which each each element contains
- information about a melting session that the coin was used in.
+ All commitments were revealed successfully. The exchange returns an array (typically consisting of only one element), in which each each element of the array contains a `LinkResponse` entry with information about a melting session that the coin was used in.
:http:statuscode:`404 Not found`:
The exchange has no linkage data for the given public key, as the coin has not
yet been involved in a refresh operation.
@@ -2258,11 +3585,19 @@ the API during normal operation.
denom_pub: RsaPublicKey;
// Exchange's blinded signature over the fresh coin.
- ev_sig: BlindedRsaSignature;
+ ev_sig: BlindedDenominationSignature;
// Blinded coin.
coin_ev : CoinEnvelope;
+ // Values contributed by the exchange during the
+ // withdraw operation (see /csr-melt).
+ ewv: ExchangeWithdrawValue;
+
+ // Offset of this coin in the refresh operation.
+ // Input needed to derive the private key.
+ coin_idx: Integer;
+
// Signature made by the old coin over the refresh request.
// Signs over a `TALER_CoinLinkSignaturePS`.
link_sig: EddsaSignature;
@@ -2292,11 +3627,10 @@ in using this API.
exchange. The exchange MUST return a 307 or 308 redirection to the correct
base URL if this is the case.
- Depending whether ``$COIN_PUB`` is a withdrawn coin or a refreshed coin,
- the remaining amount on the coin will be credited either on the reserve or
- the old coin that ``$COIN_PUB`` was withdrawn/refreshed from.
+ The remaining amount on the coin will be credited to the reserve
+ that ``$COIN_PUB`` was withdrawn from.
- Note that the original withdrawal/refresh fees will **not** be recouped.
+ Note that the original withdrawal fees will **not** be recouped.
**Request:** The request body must be a `RecoupRequest` object.
@@ -2304,13 +3638,14 @@ in using this API.
**Response:**
:http:statuscode:`200 OK`:
- The request was successful, and the response is a `RecoupConfirmation`.
+ The request was successful, and the response is a `RecoupWithdrawalConfirmation`.
Note that repeating exactly the same request
will again yield the same response, so if the network goes down during the
transaction or before the client can commit the coin signature to disk, the
coin is not lost.
- :http:statuscode:`401 Unauthorized`:
+ :http:statuscode:`403 Forbidden`:
The coin's signature is invalid.
+ This response comes with a standard `ErrorDetail` response.
:http:statuscode:`404 Not found`:
The denomination key is unknown, or the blinded
coin is not known to have been withdrawn.
@@ -2321,8 +3656,7 @@ in using this API.
residual value, or because the same public key of the coin has been
previously used with a different denomination. Which case it is
can be decided by looking at the error code
- (``TALER_EC_EXCHANGE_RECOUP_COIN_BALANCE_ZERO`` or
- ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY``).
+ (usually ``TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS``).
The response is a `DepositDoubleSpendError`.
:http:statuscode:`410 Gone`:
The requested denomination key is not yet or no longer valid.
@@ -2336,49 +3670,120 @@ in using this API.
.. ts:def:: RecoupRequest
interface RecoupRequest {
- // Hash of denomination public key (RSA), specifying the type of coin the client
+ // Hash of denomination public key, specifying the type of coin the client
// would like the exchange to pay back.
denom_pub_hash: HashCode;
// Signature over the `coin public key <eddsa-coin-pub>` by the denomination.
- denom_sig: RsaSignature;
+ denom_sig: DenominationSignature;
- // Coin's blinding factor.
- coin_blind_key_secret: RsaBlindingKeySecret;
+ // Exchange-contributed values during the refresh
+ // operation (see /csr-withdraw).
+ ewv: ExchangeWithdrawValue;
// Signature of `TALER_RecoupRequestPS` created with
// the `coin's private key <coin-priv>`.
coin_sig: EddsaSignature;
- // Was the coin refreshed (and thus the recoup should go to the old coin)?
- // While this information is technically redundant, it helps the exchange
- // to respond faster.
- // *Optional* (for backwards compatibility); if absent, ``false`` is assumed.
- refreshed?: boolean;
- }
-
+ // Coin's blinding factor.
+ coin_blind_key_secret: DenominationBlindingKeySecret;
- .. ts:def:: RecoupConfirmation
+ // Nonce that was used by the exchange to derive
+ // its private inputs from during withdraw. Only
+ // present if the cipher of the revoked denomination
+ // is of type Clause-Schnorr (CS).
+ cs_nonce?: CSNonce;
+ }
- type RecoupConfirmation = | RecoupRefreshConfirmation
- | RecoupWithdrawalConfirmation;
.. ts:def:: RecoupWithdrawalConfirmation
interface RecoupWithdrawalConfirmation {
- // Tag to distinguish the `RecoupConfirmation` response type.
- refreshed: false;
-
// Public key of the reserve that will receive the recoup.
reserve_pub: EddsaPublicKey;
}
+
+.. http:post:: /coins/$COIN_PUB/recoup-refresh
+
+ Demand that a coin be refunded via wire transfer to the original owner.
+
+ The base URL for ``/coins/``-requests may differ from the main base URL of the
+ exchange. The exchange MUST return a 307 or 308 redirection to the correct
+ base URL if this is the case.
+
+ The remaining amount on the coin will be credited to
+ the old coin that ``$COIN_PUB`` was refreshed from.
+
+ Note that the original refresh fees will **not** be recouped.
+
+
+ **Request:** The request body must be a `RecoupRefreshRequest` object.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The request was successful, and the response is a `RecoupRefreshConfirmation`.
+ Note that repeating exactly the same request
+ will again yield the same response, so if the network goes down during the
+ transaction or before the client can commit the coin signature to disk, the
+ coin is not lost.
+ :http:statuscode:`403 Forbidden`:
+ The coin's signature is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ The denomination key is unknown, or the blinded
+ coin is not known to have been withdrawn.
+ If the denomination key is unknown, the response will be
+ a `DenominationUnknownMessage`.
+ :http:statuscode:`409 Conflict`:
+ The operation is not allowed as the coin has insufficient
+ residual value, or because the same public key of the coin has been
+ previously used with a different denomination. Which case it is
+ can be decided by looking at the error code
+ (usually ``TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_BALANCE``).
+ The response is a `DepositDoubleSpendError`.
+ :http:statuscode:`410 Gone`:
+ The requested denomination key is not yet or no longer valid.
+ It either before the validity start, past the expiration or was not yet revoked. The response is a
+ `DenominationExpiredMessage`. Clients must evaluate
+ the error code provided to understand which of the
+ cases this is and handle it accordingly.
+
+ **Details:**
+
+ .. ts:def:: RecoupRefreshRequest
+
+ interface RecoupRefreshRequest {
+ // Hash of denomination public key, specifying the type of coin the client
+ // would like the exchange to pay back.
+ denom_pub_hash: HashCode;
+
+ // Signature over the `coin public key <eddsa-coin-pub>` by the denomination.
+ denom_sig: DenominationSignature;
+
+ // Exchange-contributed values during the refresh
+ // operation (see /csr-melt).
+ ewv: ExchangeWithdrawValue;
+
+ // Signature of `TALER_RecoupRequestPS` created with
+ // the `coin's private key <coin-priv>`.
+ coin_sig: EddsaSignature;
+
+ // Coin's blinding factor.
+ coin_blind_key_secret: DenominationBlindingKeySecret;
+
+ // Nonce that was used by the exchange to derive
+ // its private inputs from during withdraw. Only
+ // present if the cipher of the revoked denomination
+ // is of type Clause-Schnorr (CS).
+ cs_nonce?: CSNonce;
+ }
+
+
.. ts:def:: RecoupRefreshConfirmation
interface RecoupRefreshConfirmation {
- // Tag to distinguish the `RecoupConfirmation` response type.
- refreshed: true;
-
// Public key of the old coin that will receive the recoup.
old_coin_pub: EddsaPublicKey;
}
@@ -2443,8 +3848,8 @@ typically also view the balance.)
// Public key of the merchant (identical for all deposits).
merchant_pub: EddsaPublicKey;
- // Hash of the wire details (identical for all deposits).
- h_wire: HashCode;
+ // Hash of the payto:// account URI (identical for all deposits).
+ h_payto: PaytoHash;
// Time of the execution of the wire transfer by the exchange.
execution_time: Timestamp;
@@ -2473,12 +3878,21 @@ typically also view the balance.)
// Coin's public key, both ECDHE and EdDSA.
coin_pub: CoinPublicKey;
- // The total amount the original deposit was worth.
+ // The total amount the original deposit was worth,
+ // including fees and after applicable refunds.
deposit_value: Amount;
- // Applicable fees for the deposit.
+ // Applicable fees for the deposit, possibly
+ // reduced or waived due to refunds.
deposit_fee: Amount;
+ // Refunds that were applied to the value of
+ // this coin. Optional.
+ // Since protocol **v19**. Before, refunds were
+ // incorrectly still included in the
+ // ``deposit_value`` (!).
+ refund_total?: Amount;
+
}
.. http:get:: /deposits/$H_WIRE/$MERCHANT_PUB/$H_CONTRACT_TERMS/$COIN_PUB
@@ -2490,7 +3904,13 @@ typically also view the balance.)
**Request:**
- :query merchant_sig: EdDSA signature of the merchant made with purpose ``TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION`` over a ``TALER_DepositTrackPS``, affirming that it is really the merchant who requires obtaining the wire transfer identifier.
+ :query merchant_sig: EdDSA signature of the merchant made with purpose
+ ``TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION`` over a
+ ``TALER_DepositTrackPS``, affirming that it is really the merchant who
+ requires obtaining the wire transfer identifier.
+ :query timeout_ms=NUMBER: *Optional.* If specified, the exchange will wait
+ up to ``NUMBER`` milliseconds for completion of a deposit operation before
+ sending the HTTP response.
**Response:**
@@ -2502,8 +3922,9 @@ typically also view the balance.)
executed. Hence the exchange does not yet have a wire transfer identifier. The
merchant should come back later and ask again.
The response body is a `TrackTransactionAcceptedResponse`.
- :http:statuscode:`401 Unauthorized`:
+ :http:statuscode:`403 Forbidden`:
A signature is invalid.
+ This response comes with a standard `ErrorDetail` response.
:http:statuscode:`404 Not found`:
The deposit operation is unknown to the exchange.
@@ -2512,6 +3933,7 @@ typically also view the balance.)
.. ts:def:: TrackTransactionResponse
interface TrackTransactionResponse {
+
// Raw wire transfer identifier of the deposit.
wtid: Base32;
@@ -2521,9 +3943,6 @@ typically also view the balance.)
// The contribution of this coin to the total (without fees)
coin_contribution: Amount;
- // Total amount transferred.
- total_amount: Amount;
-
// Binary-only Signature_ with purpose ``TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE``
// over a `TALER_ConfirmWirePS`
// whereby the exchange affirms the successful wire transfer.
@@ -2539,7 +3958,28 @@ typically also view the balance.)
.. ts:def:: TrackTransactionAcceptedResponse
interface TrackTransactionAcceptedResponse {
+
+ // Legitimization target that the merchant should
+ // use to check for its KYC status using
+ // the ``/kyc-check/$REQUIREMENT_ROW/...`` endpoint.
+ // Optional, not present if the deposit has not
+ // yet been aggregated to the point that a KYC
+ // need has been evaluated.
+ requirement_row?: Integer;
+
+ // Current AML state for the target account. Non-zero
+ // values indicate that the transfer is blocked due to
+ // AML enforcement.
+ aml_decision: Integer;
+
+ // True if the KYC check for the merchant has been
+ // satisfied. False does not mean that KYC
+ // is strictly needed, unless also a
+ // legitimization_uuid is provided.
+ kyc_ok: boolean;
+
// Time by which the exchange currently thinks the deposit will be executed.
+ // Actual execution may be later if the KYC check is not satisfied by then.
execution_time: Timestamp;
}
@@ -2550,7 +3990,7 @@ typically also view the balance.)
Refunds
-------
-.. http:POST:: /coins/$COIN_PUB/refund
+.. http:post:: /coins/$COIN_PUB/refund
Undo deposit of the given coin, restoring its value.
@@ -2560,7 +4000,7 @@ Refunds
:http:statuscode:`200 OK`:
The operation succeeded, the exchange confirms that the coin can now be refreshed. The response will include a `RefundSuccess` object.
- :http:statuscode:`401 Unauthorized`:
+ :http:statuscode:`403 Forbidden`:
Merchant signature is invalid.
This response comes with a standard `ErrorDetail` response.
:http:statuscode:`404 Not found`:
@@ -2649,27 +4089,23 @@ Refunds
Wallet-to-wallet transfers
--------------------------
-.. http:GET:: /purses/$PURSE_PUB
+.. http:get:: /purses/$PURSE_PUB/merge
+.. http:get:: /purses/$PURSE_PUB/deposit
- Obtain information about a purse. The request header must
- contain a *Purse-Request-Signature*. Endpoint used by
- the party that did not create the purse.
+ Obtain information about a purse. Depending on the suffix,
+ the long-polling (if any) will wait for either a merge or
+ a deposit event.
**Request:**
- *Purse-Request-Signature*: The client must provide Base-32 encoded EdDSA signature made with ``$PURSE_PRIV``, affirming its authorization to download the purse status. The purpose used MUST be ``TALER_SIGNATURE_PURSE_STATUS_REQUEST``.
-
- :query merge_timeout_ms=NUMBER: *Optional.* If specified,
+ :query timeout_ms=NUMBER: *Optional.* If specified,
the exchange
- will wait up to ``timeout_ms`` milliseconds for completion
+ will wait up to ``NUMBER`` milliseconds for completion
of a merge operation before sending the HTTP response.
:query deposit_timeout_ms=NUMBER: *Optional.* If specified,
the exchange
- will wait up to ``timeout_ms`` milliseconds for completion
+ will wait up to ``NUMBER`` milliseconds for completion
of a deposit operation before sending the HTTP response.
- :query contract=BOOLEAN: *Optional.* If 'false' is specified,
- the exchange will not return the encrypted contract, saving
- bandwidth for clients that already know it.
**Response:**
@@ -2677,11 +4113,10 @@ Wallet-to-wallet transfers
The operation succeeded, the exchange provides details
about the purse.
The response will include a `PurseStatus` object.
- :http:statuscode:`401 Unauthorized`:
- The *Purse-Request-Signature* is invalid.
- This response comes with a standard `ErrorDetail` response.
:http:statuscode:`404 Not found`:
The purse is unknown to the exchange.
+ :http:statuscode:`410 Gone`:
+ The purse expired before the deposit or merge was completed.
**Details:**
@@ -2694,26 +4129,28 @@ Wallet-to-wallet transfers
// exceeds 'merge_value_after_fees', and a
// 'merge_request' exists for the purse, then the
// purse will (have been) merged with the account.
- total_deposit_amount: Amount;
+ balance: Amount;
- // Indicative time by which the purse expires
- // if it has not been merged into an account. At this
- // point, all of the deposits made will be auto-refunded.
+ // When does the purge expire.
purse_expiration: Timestamp;
- // Desired total amount to be merged into the reserve.
- // (excludes fees).
- merge_value_after_fees: Amount;
-
- // Indicative time at which the exchange is answering the
- // status request. Used as part of 'exchange_sig'.
- status_timestamp: Timestamp;
-
- // Deposit fees charged so far to all deposited coins.
- deposit_fees: Amount;
-
- // SHA-512 hash of the contact of the purse.
- h_contract_terms: HashCode;
+ // Time of the merge, missing if "never".
+ merge_timestamp?: Timestamp;
+
+ // Time of the deposits being complete, missing if "never".
+ // Note that this time may not be "stable": once sufficient
+ // deposits have been made, is "now" before the purse
+ // expiration, and otherwise set to the purse expiration.
+ // However, this should also not be relied upon. The key
+ // property is that it is either "never" or in the past.
+ deposit_timestamp?: Timestamp;
+
+ // Time when the purse expires and
+ // funds that were not merged are refunded
+ // on the deposited coins.
+ // FIXME: Document the exchange protocol version
+ // in which this field became available.
+ purse_expiration: Timestamp;
// EdDSA signature of the exchange over a
// `TALER_PurseStatusResponseSignaturePS`
@@ -2724,26 +4161,17 @@ Wallet-to-wallet transfers
// EdDSA public key exchange used for 'exchange_sig'.
exchange_pub: EddsaPublicKey;
- // AES-GCM Encrypted contract terms using encryption
- // key derived from DH of 'contract_pub' and the 'purse_pub'.
- // Optional, may be omitted if not desired by the client.
- e_contract_terms?: string;
-
- // If a merge request was received, information about the
- // merge request. Omitted if the purse has not yet received
- // a merge request.
- merge_request?: MergeRequest;
-
}
-.. http:POST:: /purses/$PURSE_PUB/deposit
- Deposit money into a purse. Endpoint used by the buyer.
+.. http:post:: /purses/$PURSE_PUB/create
+
+ Create a purse by depositing money into it. First step of a PUSH payment.
**Request:**
- The request body must be a `PurseRequest` object.
+ The request body must be a `PurseCreate` object.
**Response:**
@@ -2751,138 +4179,133 @@ Wallet-to-wallet transfers
The operation succeeded, the exchange confirms that all
coins were deposited into the purse.
The response will include a `PurseDepositSuccess` object.
- :http:statuscode:`202 Accepted`:
- The payment was accepted, but insufficient to reach the
- specified purse balance. If an encrypted contract was
- provided, it will have been stored in the database.
- The client should make further
- purse deposits before the expiration deadline.
- The response will include a `PurseDepositAccepted` object.
- :http:statuscode:`401 Unauthorized`:
- A coin signature is invalid. The response will
- include a `PurseDepositSignatureErrorDetail`
:http:statuscode:`403 Forbidden`:
- The server is denying the operation as a purse with a
- different contract or total amount already exists.
- This response comes with a standard `PurseConflict` response.
- :http:statuscode:`404 Not found`:
- FIXME: when exactly does this happen?
+ A coin, denomination or contract signature is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not Found`:
+ The denomination of one of the coins is unknown to the exchange.
:http:statuscode:`409 Conflict`:
The deposit operation has either failed because a coin has insufficient
residual value, or because the same public key of the coin has been
- previously used with a different denomination. Which case it is
+ previously used with a different denomination, or because a purse with
+ the same public key but different meta data was created previously.
+ Which case it is
can be decided by looking at the error code
- (``TALER_EC_EXCHANGE_DEPOSIT_INSUFFICIENT_FUNDS`` or
- ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY``).
- The fields of the response are the same in both cases.
- The request should not be repeated again with this coin.
- In this case, the response is a `PurseDepositDoubleSpendError`.
- If the value of all successful coins is below the purse fee,
- the exchange may not setup the purse at all. The encrypted
- contract will not have been associated with the purse if this
- status code is returned. However, all coins that were not
- double-spent will have been deposited into the purse.
+ (``TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS`` or
+ ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY`` or
+ ``TALER_EC_EXCHANGE_PURSE_CREATE_CONFLICTING_META_DATA`` or
+ ``TALER_EC_EXCHANGE_PURSE_DEPOSIT_CONFLICTING_META_DATA`` or
+ ``TALER_EC_EXCHANGE_PURSE_ECONTRACT_CONFLICTING_META_DATA``).
+ The specific fields of the response depend on the error code
+ and include the signatures (and what was signed over) proving the
+ conflict.
:http:statuscode:`425 Too Early`:
This response type is used if the given purse expiration time
is too far in the future (at least from the perspective
of the exchange). Thus, retrying at a later time may
- succeed. The client should look at the ``Date:`` header of the response to see if a minor time difference is to blame and possibly adjust the request accordingly.
+ succeed. The client should look at the ``Date:`` header
+ of the response to see if a minor time difference is to
+ blame and possibly adjust the request accordingly.
+ (Note: this status code is not yet used.)
**Details:**
- .. ts:def:: PurseRequest
+ .. ts:def:: PurseCreate
- interface PurseRequest {
+ interface PurseCreate {
+
+ // Total value of the purse, excluding fees.
+ amount: Amount;
+
+ // Minimum age required for all coins deposited into the purse.
+ min_age: Integer;
+
+ // Optional encrypted contract, in case the buyer is
+ // proposing the contract and thus establishing the
+ // purse with the payment.
+ econtract?: EncryptedContract;
+
+ // EdDSA public key used to approve merges of this purse.
+ merge_pub: EddsaPublicKey;
// EdDSA signature of the purse over a
// `TALER_PurseRequestSignaturePS`
- // of purpose ``TALER_SIGNATURE_PURSE_REQUEST``
+ // of purpose ``TALER_SIGNATURE_WALLET_PURSE_CREATE``
// confirming the key
// invariants associated with the purse.
// (amount, h_contract_terms, expiration).
purse_sig: EddsaSignature;
- // Total amount to be paid into the purse.
- // Clients may make several requests, i.e. if a
- // first request failed with a double-spending error.
- // The exchange will confirm the creation of the
- // purse once the amount given here is reached.
- merge_value_after_fees: Amount;
-
// SHA-512 hash of the contact of the purse.
h_contract_terms: HashCode;
- // Client-side timestamp of when the payment was made.
- payment_timestamp: Timestamp;
+ // Array of coins being deposited into the purse.
+ // Maximum length is 128.
+ deposits: PurseDeposit[];
// Indicative time by which the purse should expire
// if it has not been merged into an account. At this
// point, all of the deposits made will be auto-refunded.
purse_expiration: Timestamp;
- // Optional encrypted contract, in case the buyer is
- // proposing the contract and thus establishing the
- // purse with the payment.
- contract?: EncryptedContract;
-
- // Array of coins being deposited into the purse.
- // Maximum length is 128.
- deposits: PurseDeposit[];
}
- .. ts:def:: EncryptedContract
+ .. ts:def:: EncryptedContract
interface EncryptedContract {
- // ECDH contract_public key used to encrypt the contract.
- // Optional as the contract terms may already be known
- // to the exchange or the other wallet from a different
- // interaction.
- contract_pub: TALER_EcdhEphemeralPublicKeyP;
+ // Encrypted contract.
+ econtract: string;
+
+ // Signature over the (encrypted) contract.
+ econtract_sig: EddsaSignature;
+
+ // Ephemeral public key for the DH operation to decrypt the encrypted contract.
+ contract_pub: EddsaPublicKey;
- // AES-GCM Encrypted contract terms using encryption
- // key derived from DH of ``contract_pub`` and the ``purse_pub``.
- // Optional as the contract terms may already be known
- // to the exchange or the other wallet from a different
- // interaction.
- e_contract_terms: string;
}
.. ts:def:: PurseDeposit
interface PurseDeposit {
- // Public key of the coin being deposited into the purse.
- coin_pub: EddsaPublicKey;
-
// Amount to be deposited, can be a fraction of the
// coin's total value.
- contribution: Amount;
+ amount: Amount;
// Hash of denomination RSA key with which the coin is signed.
denom_pub_hash: HashCode;
// Exchange's unblinded RSA signature of the coin.
- ub_sig: RsaSignature;
+ ub_sig: DenominationSignature;
+
+ // Age commitment for the coin, if the denomination is age-restricted.
+ age_commitment?: AgeCommitment;
+
+ // Attestation for the minimum age, if the denomination is age-restricted.
+ attest?: Attestation;
// Signature over `TALER_PurseDepositSignaturePS`
- // of purpose ``TALER_SIGNATURE_PURSE_DEPOSIT``
+ // of purpose ``TALER_SIGNATURE_WALLET_PURSE_DEPOSIT``
// made by the customer with the
// `coin's private key <coin-priv>`.
coin_sig: EddsaSignature;
+ // Public key of the coin being deposited into the purse.
+ coin_pub: EddsaPublicKey;
+
}
.. ts:def:: PurseDepositSuccess
interface PurseDepositSuccess {
- // Total amount paid into the purse.
- total_purse_amount: Amount;
+ // Total amount deposited into the purse so far (without fees).
+ total_deposited: Amount;
- // Total deposit fees charged.
- total_deposit_fees: Amount;
+ // Time at the exchange.
+ exchange_timestamp: Timestamp;
// EdDSA signature of the exchange affirming the payment,
// of purpose ``TALER_SIGNATURE_PURSE_DEPOSIT_CONFIRMED``
@@ -2896,39 +4319,27 @@ Wallet-to-wallet transfers
}
- .. ts:def:: PurseDepositAccepted
-
- interface PurseDepositAccepted {
-
- // Total amount paid so far into the purse, in this
- // and previous requests.
- total_amount_deposited: Amount;
-
- // Total amount contributed by the current request.
- total_amount_contributed: Amount;
-
- }
-
.. ts:def:: PurseConflict
- // Union discriminated by the "type" field.
+ // Union discriminated by the "code" field.
type PurseConflict =
- | PurseMergeConflict
- | PurseRequestConflict;
-
- .. ts:def:: PurseMergeConflict
+ | DepositDoubleSpendError
+ | PurseCreateConflict
+ | PurseDepositConflict
+ | PurseContractConflict;
- interface PurseMergeConflict {
- type: "MERGE";
+ .. ts:def:: PurseCreateConflict
- // SHA-512 hash of the contact of the purse.
- h_contract_terms: HashCode;
+ interface PurseCreateConflict {
+ // Must be equal to TALER_EC_EXCHANGE_PURSE_CREATE_CONFLICTING_META_DATA
+ code: Integer;
- // Hash of the wire details of the reserve.
- h_wire: HashCode;
+ // Total amount to be merged into the reserve.
+ // (excludes fees).
+ amount: Amount;
- // Reserve merging the purse.
- reserve_pub: EddsaPublicKey;
+ // Minimum age required for all coins deposited into the purse.
+ min_age: Integer;
// Indicative time by which the purse should expire
// if it has not been merged into an account. At this
@@ -2936,136 +4347,125 @@ Wallet-to-wallet transfers
// auto-refunded.
purse_expiration: Timestamp;
- // When was the merge request generated.
- merge_timestamp: Timestamp;
-
- // Total amount to be merged into the reserve.
- // (excludes fees).
- merge_value_after_fees: Amount;
-
// EdDSA signature of the purse over
// `TALER_PurseMergeSignaturePS` of
- // purpose ``TALER_SIGNATURE_PURSE_MERGE``
+ // purpose ``TALER_SIGNATURE_WALLET_PURSE_MERGE``
// confirming that the
// above details hold for this purse.
purse_sig: EddsaSignature;
+
+ // SHA-512 hash of the contact of the purse.
+ h_contract_terms: HashCode;
+
+ // EdDSA public key used to approve merges of this purse.
+ merge_pub: EddsaPublicKey;
}
- .. ts:def:: PurseRequestConflict
+ .. ts:def:: PurseDepositConflict
- interface PurseRequestConflict {
- type: "REQUEST";
+ interface PurseDepositConflict {
+ // Must be equal to TALER_EC_EXCHANGE_PURSE_DEPOSIT_CONFLICTING_META_DATA
+ code: Integer;
- // SHA-512 hash of the contact of the purse.
- h_contract_terms: HashCode;
+ // Public key of the coin being deposited into the purse.
+ coin_pub: EddsaPublicKey;
- // Indicative time by which the purse should expire
- // if it has not been merged into an account. At this
- // point, all of the deposits made should be
- // auto-refunded.
- purse_expiration: Timestamp;
+ // Signature over `TALER_PurseDepositSignaturePS`
+ // of purpose ``TALER_SIGNATURE_WALLET_PURSE_DEPOSIT``
+ // made by the customer with the
+ // `coin's private key <coin-priv>`.
+ coin_sig: EddsaSignature;
- // Total amount to be paid into the purse as per
- // the previous request.
- total_purse_amount: Amount;
+ // Target exchange URL for the purse. Not present for the
+ // same exchange.
+ partner_url?: string;
- // EdDSA signature of the purse over
- // `TALER_PurseRequestSignaturePS` of
- // purpose ``TALER_SIGNATURE_PURSE_REQUEST``
- // confirming that the
- // above details hold for this purse.
- purse_sig: EddsaSignature;
+ // Amount to be contributed to the purse by this coin.
+ amount: Amount;
}
- .. ts:def:: PurseDepositDoubleSpendError
+ .. ts:def:: PurseContractConflict
- interface DepositDoubleSpendError {
- // Taler error code.
- code: number;
+ interface PurseContractConflict {
+ // Must be equal to TALER_EC_EXCHANGE_PURSE_ECONTRACT_CONFLICTING_META_DATA
+ code: Integer;
- // Human-readable description of the error, i.e. "insufficient funds".
- hint?: string;
+ // Hash of the encrypted contract.
+ h_econtract: HashCode;
- // Total amount contributed by the current request.
- // Note that some coins may have been successfully
- // deposited into the purse, so the total amount
- // from these coins is listed here.
- total_amount_contributed: Amount;
+ // Signature over the contract.
+ econtract_sig: EddsaSignature;
+
+ // Ephemeral public key for the DH operation to decrypt the contract.
+ contract_pub: EddsaPublicKey;
- // Public keys of coins that could not be deposited
- // into the purse, mapped to the coin's histories.
- coin_map: EddsaPublicKey -> CoinSpendHistoryItem[];
}
- .. ts:def:: PurseDepositSignatureErrorDetail
- interface PurseDepositSignatureErrorDetail {
- // Taler error code, summarizing the problem.
- // Note that for problems about specific
- // coins, the 'coin_error_map' should be consulted.
- // The 'coin_error_map' will be empty if the
- // 'purse_sig' was invalid. In this case,
- // the coins will not even have been checked by
- // the exchange.
- code: number;
+.. http:delete:: /purses/$PURSE_PUB
- // Human-readable description of the error, i.e. "invalid siganture".
- hint?: string;
+ Delete a purse that is unmerged and not yet expired. Refunds any money that
+ is already in the purse.
- // Total amount contributed by the current request.
- // Note that some coins may have been successfully
- // deposited into the purse, so the total amount
- // from these coins is listed here.
- total_amount_contributed: Amount;
+ **Request:**
- // Public keys of coins that could not be deposited
- // into the purse, mapped to the coin's histories.
- coin_error_map: EddsaPublicKey -> ErrorDetail[];
- }
+ The request body must be empty, as recommended for HTTP delete in general.
+ To authorize the request, the header must contain a
+ ``Taler-Purse-Signature: $PURSE_SIG`` where ``$PURSE_SIG`` is the Crockford base32-encoded
+ EdDSA signature of purpose TALER_SIGNATURE_WALLET_PURSE_DELETE.
+
+ **Response:**
+
+ :http:statuscode:`204 No Content`:
+ The operation succeeded, the exchange confirms that the purse
+ was deleted.
+ :http:statuscode:`403 Forbidden`:
+ The signature is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not Found`:
+ The purse is not known. Might have already been deleted previously.
+ :http:statuscode:`409 Conflict`:
+ It is too late to delete the purse, its fate (merge or expiration)
+ was already decided.
-.. http:POST:: /purses/$PURSE_PUB/merge
+.. http:post:: /purses/$PURSE_PUB/merge
Merge purse with account, adding the value of the purse into
- the account. Endpoint to be used by the seller.
+ the account. Endpoint to be used by the receiver of a PUSH payment.
**Request:**
The request body must be a `MergeRequest` object.
- :query timeout_ms=NUMBER: *Optional.* If specified, the exchange will
- wait up to ``timeout_ms`` milliseconds to receive payment before
- reporting on the completion of merge operation. Basically
- forstalls returning a 202 response for up to timeout milliseconds
- to possibly return a 200 response instead.
-
**Response:**
:http:statuscode:`200 OK`:
The operation succeeded, the exchange confirms that the
funds were merged into the account.
The response will include a `MergeSuccess` object.
- :http:statuscode:`202 Accepted`:
- The operation succeeded, the exchange confirms that the
- merge request is valid. Alas, the purse was still not
- funded and thus the actual merge is delayed.
- The response will include a `MergeAccepted` object.
- :http:statuscode:`401 Unauthorized`:
- Account signature is invalid.
+ :http:statuscode:`402 Payment Required`:
+ The purse is not yet full and more money needs to be deposited
+ before the merge can be made.
+ :http:statuscode:`403 Forbidden`:
+ The signature of the merge request or the reserve was invalid.
This response comes with a standard `ErrorDetail` response.
:http:statuscode:`404 Not found`:
- The refund operation failed as we could not find the purse.
+ The merge operation failed as we could not find the purse
+ or the partner exchange.
This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`409 Conflict`:
+ The purse was already merged into a different reserve.
+ The response will include a `MergeConflict` object.
:http:statuscode:`410 Gone`:
The purse has already expired and thus can no longer be merged.
This response comes with a standard `ErrorDetail` response.
- :http:statuscode:`429 Too Many Requests`:
- This account is not at this exchange, has not yet passed the
- KYC checks, or it has exceeded the number of open purses.
- The client must include payment to create another purse or
- wait until existing purses have expired.
+ :http:statuscode:`451 Unavailable For Legal Reasons`:
+ This account has not yet passed the KYC checks.
+ The client must pass KYC checks before proceeding with the merge.
+ The response will be an `KycNeededRedirect` object.
**Details:**
@@ -3082,32 +4482,14 @@ Wallet-to-wallet transfers
// Must be of purpose ``TALER_SIGNATURE_ACCOUNT_MERGE``
reserve_sig: EddsaSignature;
- // EdDSA signature of the purse private key affirming the merge
+ // EdDSA signature of the merge private key affirming the merge
// over a `TALER_PurseMergeSignaturePS`.
// Must be of purpose ``TALER_SIGNATURE_PURSE_MERGE``.
- purse_sig: EddsaSignature;
-
- // Minimum amount that must be credited to the reserve, that is
- // the total value of the purse minus the deposit fees.
- // If the deposit fees are lower, the contribution to the
- // reserve can be higher!
- merge_value_after_fees: Amount;
-
- // SHA-512 hash of the contact of the purse.
- h_contract_terms: HashCode;
+ merge_sig: EddsaSignature;
// Client-side timestamp of when the merge request was made.
merge_timestamp: Timestamp;
- // Indicative time by which the purse should expire
- // if it has not been paid.
- purse_expiration: Timestamp;
-
- // Optional encrypted contract, in case the seller is
- // proposing the contract and thus establishing the
- // purse with the payment.
- contract?: EncryptedContract;
-
}
.. ts:def:: MergeSuccess
@@ -3117,13 +4499,10 @@ Wallet-to-wallet transfers
// Amount merged (excluding deposit fees).
merge_amount: Amount;
- // SHA-512 hash of the contact of the purse.
- h_contract_terms: HashCode;
-
// Time at which the merge came into effect.
// Maximum of the "payment_timestamp" and the
// "merge_timestamp".
- contract_time: Timestamp;
+ exchange_timestamp: Timestamp;
// EdDSA signature of the exchange affirming the merge of
// purpose ``TALER_SIGNATURE_PURSE_MERGE_SUCCESS``
@@ -3136,119 +4515,267 @@ Wallet-to-wallet transfers
}
- .. ts:def:: MergeAccepted
+ .. ts:def:: MergeConflict
- interface MergeAccepted {
+ interface MergeConflict {
- // The number of remaining purses that can still be opened
- // under the given account.
- remaining_purses: Integer;
+ // Client-side timestamp of when the merge request was made.
+ merge_timestamp: Timestamp;
+ // EdDSA signature of the purse private key affirming the merge
+ // over a `TALER_PurseMergeSignaturePS`.
+ // Must be of purpose ``TALER_SIGNATURE_PURSE_MERGE``.
+ merge_sig: EddsaSignature;
+
+ // Base URL of the exchange receiving the payment, only present
+ // if the exchange hosting the reserve is not this exchange.
+ partner_url?: string;
+
+ // Public key of the reserve that the purse was merged into.
+ reserve_pub: EddsaPublicKey;
}
-.. http:POST:: /reserves/$RESERVE_PUB/kyc
- Upgrade a reserve to an *account*. The reserve must
- (from wire transfers or merges of purses) already have a
- sufficient balance to cover the KYC fee. The signature
- affirms that the KYC fee can and should be charged to the reserve.
- The request always updates the payto URI associated with
- the reserve, even if the KYC process fails or is not completed.
+.. http:post:: /reserves/$RESERVE_PUB/purse
- **Request:** The request body must be a `AccountSetupRequest` object.
+ Create purse for an account. First step of a PULL payment.
- :query timeout_ms=NUMBER: *Optional.* If specified, the exchange will
- wait up to ``timeout_ms`` milliseconds for the KYC gateway to
- confirm completion of the KYC process.
+ **Request:**
+
+ The request body must be a `ReservePurseRequest` object.
**Response:**
- :http:statuscode:`200 Ok`:
- The operation succeeded, the exchange confirms that the account
- can now be used.
- The response will be an `AccountKycStatus` object.
- :http:statuscode:`202 Accepted`:
- The user should be redirected to the provided location to perform
- the required KYC checks to open the account. Afterwards, the
- request should be repeated.
- The response will be an `AccountKycRedirect` object.
- :http:statuscode:`504 Gateway Timeout`:
- The exchange did not receive a confirmation from the KYC service
- within the specified time period. Used when long-polling for the
- result.
+ :http:statuscode:`200 OK`:
+ The operation succeeded, the exchange confirms that the
+ purse was allocated.
+ The response will include a `PurseDepositSuccess` object.
+ :http:statuscode:`402 Payment Required`:
+ The account needs to contain more funding to create more purses.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`403 Forbidden`:
+ Account or contract signature is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ The purse creation operation failed as we could not find the reserve.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`409 Conflict`:
+ The purse creation failed because a purse with
+ the same public key but different meta data was
+ created previously. Which specific conflict it is
+ can be decided by looking at the error code
+ (``TALER_EC_EXCHANGE_PURSE_CREATE_CONFLICTING_META_DATA`` or
+ ``TALER_EC_EXCHANGE_PURSE_DEPOSIT_CONFLICTING_META_DATA`` or
+ ``TALER_EC_EXCHANGE_PURSE_ECONTRACT_CONFLICTING_META_DATA``).
+ The specific fields of the response depend on the error code
+ and include the signatures (and what was signed over) proving the
+ conflict.
+ The response will be a `PurseConflict` response
+ (but not a `DepositDoubleSpendError`).
+ :http:statuscode:`451 Unavailable For Legal Reasons`:
+ This account has not yet passed the KYC checks.
+ The client must pass KYC checks before proceeding with the merge.
+ The response will be an `KycNeededRedirect` object.
**Details:**
- .. ts:def:: AccountSetupRequest
+ .. ts:def:: ReservePurseRequest
- interface AccountSetupRequest {
+ interface ReservePurseRequest {
- // Time of the request to perform the KYC. Determines
- // the KYC fee charged by the exchange. Must be
- // reasonably close to the current time of the exchange.
- kyc_timestamp: Timestamp;
+ // Minimum amount that must be credited to the reserve, that is
+ // the total value of the purse minus the deposit fees.
+ // If the deposit fees are lower, the contribution to the
+ // reserve can be higher!
+ purse_value: Amount;
- // Bank account to be associated with the account.
- // Can be 'payto://void/' to not associate the
- // account with any bank account. In this case,
- // closing the account will result in the balance
- // being forfeit. If the provided wire method is
- // not supported by the exchange *and* not 'void',
- // this is a ``Bad Request`` (HTTP status 400).
- payto_uri: string;
+ // Minimum age required for all coins deposited into the purse.
+ min_age: Integer;
- // EdDSA signature of the reserve affirming the request
- // to create the account, must be of purpose
- // ``TALER_SIGNATURE_ACCOUNT_SETUP_REQUEST``
- // and over `TALER_AccountSetupRequestSignaturePS`.
- reserve_sig: EddsaPublicKey;
+ // Purse fee the reserve owner is willing to pay
+ // for the purse creation. Optional, if not present
+ // the purse is to be created from the purse quota
+ // of the reserve.
+ purse_fee: Amount;
+
+ // Optional encrypted contract, in case the buyer is
+ // proposing the contract and thus establishing the
+ // purse with the payment.
+ econtract?: EncryptedContract;
+
+ // EdDSA public key used to approve merges of this purse.
+ merge_pub: EddsaPublicKey;
+
+ // EdDSA signature of the purse private key affirming the merge
+ // over a `TALER_PurseMergeSignaturePS`.
+ // Must be of purpose ``TALER_SIGNATURE_PURSE_MERGE``.
+ merge_sig: EddsaSignature;
+
+ // EdDSA signature of the account/reserve affirming the merge.
+ // Must be of purpose ``TALER_SIGNATURE_WALLET_ACCOUNT_MERGE``
+ reserve_sig: EddsaSignature;
+
+ // Purse public key.
+ purse_pub: EddsaPublicKey;
+
+ // EdDSA signature of the purse over
+ // `TALER_PurseRequestSignaturePS` of
+ // purpose ``TALER_SIGNATURE_PURSE_REQUEST``
+ // confirming that the
+ // above details hold for this purse.
+ purse_sig: EddsaSignature;
+
+ // SHA-512 hash of the contact of the purse.
+ h_contract_terms: HashCode;
+
+ // Client-side timestamp of when the merge request was made.
+ merge_timestamp: Timestamp;
+
+ // Indicative time by which the purse should expire
+ // if it has not been paid.
+ purse_expiration: Timestamp;
}
- .. ts:def:: AccountKycStatus
- interface AccountKycStatus {
+.. http:post:: /purses/$PURSE_PUB/deposit
- // Current time of the exchange, used as part of
- // what the exchange signs over.
- now: Timestamp;
+ Deposit money into a purse. Used by the buyer for a PULL payment.
- // EdDSA signature of the exchange affirming the account
- // is KYC'ed, must be of purpose
- // ``TALER_SIGNATURE_ACCOUNT_SETUP_SUCCESS``
- // and over `TALER_AccountSetupRequestSignaturePS`.
- exchange_sig: EddsaSignature;
+ **Request:**
- // public key used to create the signature.
- exchange_pub: EddsaPublicKey;
+ The request body must be a `PurseDeposits` object.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The operation succeeded, the exchange confirms that all
+ coins were deposited into the purse.
+ The response will include a `PurseDepositSuccess` object.
+ :http:statuscode:`403 Forbidden`:
+ A coin or denomination signature is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ The purse is unknown.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`409 Conflict`:
+ The deposit operation has either failed because a coin has insufficient
+ residual value, or because the same public key of the coin has been
+ previously used with a different denomination. Which case it is
+ can be decided by looking at the error code
+ (``TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS`` or
+ ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY`` or
+ ``TALER_EC_EXCHANGE_PURSE_DEPOSIT_CONFLICTING_META_DATA``).
+ This response comes with a standard `PurseConflict` response
+ (alas some cases are impossible).
+ :http:statuscode:`410 Gone`:
+ The purse has expired.
+
+
+ **Details:**
+
+ .. ts:def:: PurseDeposits
+
+ interface PurseDeposits {
+
+ // Array of coins to deposit into the purse.
+ deposits: PurseDeposit[];
}
- .. ts:def:: AccountKycRedirect
+ .. ts:def:: PurseDeposit
- interface AccountKycRedirect {
+ interface PurseDeposit {
- // URL that the user should open in a browser to
- // proceed with the KYC process.
- kyc_url: string;
+ // Amount to be deposited, can be a fraction of the
+ // coin's total value.
+ amount: Amount;
+
+ // Hash of denomination RSA key with which the coin is signed.
+ denom_pub_hash: HashCode;
+
+ // Exchange's unblinded RSA signature of the coin.
+ ub_sig: DenominationSignature;
+
+ // Age commitment for the coin, if the denomination is age-restricted.
+ age_commitment?: AgeCommitment;
+
+ // Attestation for the minimum age, if the denomination is age-restricted.
+ attest?: Attestation;
+
+ // Signature over `TALER_PurseDepositSignaturePS`
+ // of purpose ``TALER_SIGNATURE_WALLET_PURSE_DEPOSIT``
+ // made by the customer with the
+ // `coin's private key <coin-priv>`.
+ coin_sig: EddsaSignature;
+
+ // Public key of the coin being deposited into the purse.
+ coin_pub: EddsaPublicKey;
+
+ }
+
+ .. ts:def:: PurseDepositSuccess
+
+ interface PurseDepositSuccess {
+
+ // Total amount paid into the purse.
+ total_deposited: Amount;
+
+ // Total amount expected in the purse.
+ purse_value_after_fees: Amount;
+
+ // Time at which the deposit came into effect.
+ exchange_timestamp: Timestamp;
+
+ // Indicative time by which the purse should expire
+ // if it has not been merged into an account. At this
+ // point, all of the deposits made will be auto-refunded.
+ purse_expiration: Timestamp;
+
+ // SHA-512 hash of the contact of the purse.
+ h_contract_terms: HashCode;
+
+ // EdDSA signature of the exchange affirming the payment,
+ // of purpose ``TALER_SIGNATURE_PURSE_DEPOSIT_CONFIRMED``
+ // over a `TALER_PurseDepositConfirmedSignaturePS`.
+ // Signs over the above and the purse public key and
+ // the hash of the contract terms.
+ exchange_sig: EddsaSignature;
+
+ // public key used to create the signature.
+ exchange_pub: EddsaPublicKey;
}
+ .. ts:def:: AgeCommitment
+ // AgeCommitment is an array of public keys, one for each age group of the
+ // age-restricted denomination.
+ type AgeCommitment = Edx25519PublicKey[];
+ .. ts:def:: Attestation
+ // An attestation for a minimum age is an Edx25519 signature of the age
+ // with purpose ``TALER_SIGNATURE_WALLET_AGE_ATTESTATION``.
+ type Attestation = string;
.. _exchange_wads:
+----
Wads
-^^^^
+----
+
+ .. note::
+
+ This is a draft API that is not yet implemented.
+
These endpoints are used to manage exchange-to-exchange payments in support of
wallet-to-wallet payments. Only another exchange should access this endpoint.
-.. http:GET:: /wads/$WAD_ID
+.. http:get:: /wads/$WAD_ID
Obtain information about a wad.
@@ -3330,3 +4857,633 @@ wallet-to-wallet payments. Only another exchange should access this endpoint.
// Wad fees that was charged to the purse.
wad_fees: Amount;
}
+
+
+------------------
+KYC status updates
+------------------
+
+This section describes endpoints used to set up, complete and
+inquire about KYC operations performed by an exchange for
+regulatory compliance.
+
+.. http:post:: /kyc-wallet
+
+ Setup KYC identification for a wallet. Returns the KYC UUID.
+ This endpoint is used by compliant Taler wallets when they
+ are about to hit the balance threshold and thus need to have
+ the customer provide their personal details to the exchange.
+ The wallet is identified by its long-lived reserve public key
+ (which is used for P2P payments, not for withdrawals).
+
+ **Request:**
+
+ The request body must be a `WalletKycRequest` object.
+
+ **Response:**
+
+ :http:statuscode:`204 No Content`:
+ KYC is disabled at this exchange, or the balance
+ is below the threshold that requires KYC, or this
+ wallet already satisfied the KYC check for the
+ given balance.
+ :http:statuscode:`403 Forbidden`:
+ The provided signature is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`451 Unavailable for Legal Reasons`:
+ The wallet must undergo a KYC check. A KYC ID was created.
+ The response will be a `WalletKycUuid` object.
+
+ **Details:**
+
+ .. ts:def:: WalletKycRequest
+
+ interface WalletKycRequest {
+
+ // Balance threshold (not necessarily exact balance)
+ // to be crossed by the wallet that (may) trigger
+ // additional KYC requirements.
+ balance: Amount;
+
+ // EdDSA signature of the wallet affirming the
+ // request, must be of purpose
+ // ``TALER_SIGNATURE_WALLET_ACCOUNT_SETUP``
+ reserve_sig: EddsaSignature;
+
+ // long-term wallet reserve-account
+ // public key used to create the signature.
+ reserve_pub: EddsaPublicKey;
+ }
+
+ .. ts:def:: WalletKycUuid
+
+ interface WalletKycUuid {
+
+ // UUID that the wallet should use when initiating
+ // the KYC check.
+ requirement_row: number;
+
+ // Hash of the payto:// account URI for the wallet.
+ h_payto: PaytoHash;
+
+ }
+
+
+.. http:get:: /kyc-check/$REQUIREMENT_ROW/$H_PAYTO/$USERTYPE
+
+ Checks the KYC status of a particular payment target and possibly begins the
+ KYC process. This endpoint is used by wallets or merchants that have been
+ told about a KYC requirement and now want to check if the KYC requirement
+ has been fulfilled. Long-polling may be used to instantly observe a change
+ in the KYC requirement status.
+
+ Returns the current KYC status of the requirement process and, if negative,
+ returns the URL where the KYC process can be initiated. The
+ ``$REQUIREMENT_ROW`` must have been returned previously from an exchange API
+ endpoint that determined that KYC was needed. The ``$H_PATYO`` must be the
+ hash of the "payto://" URI of the payment target. The ``$USERTYPE`` states
+ whether the entity to perform the KYC is an "individual" or a "business".
+
+ **Request:**
+
+ :query timeout_ms=NUMBER: *Optional.* If specified, the exchange will
+ wait up to ``timeout_ms`` milliseconds if the payment target
+ is currently not legitimized. Ignored if the payment target
+ is already legitimized. Note that the legitimization would be
+ triggered by another request to the same endpoint with a valid
+ ``token``.
+
+ **Response:**
+
+ :http:statuscode:`200 Ok`:
+ The KYC operation succeeded, the exchange confirms that the
+ payment target already authorized to transact.
+ The response will be an `AccountKycStatus` object.
+ :http:statuscode:`202 Accepted`:
+ The user should be redirected to the provided location to perform
+ the required KYC checks to satisfy the legal requirements. Afterwards, the
+ ``/kyc-check/`` request should be repeated to check whether the
+ user has completed the process.
+ The response will be an `AccountKycRedirect` object.
+ :http:statuscode:`204 No content`:
+ The exchange is not configured to perform KYC and thus
+ the legal requirements are already satisfied.
+ :http:statuscode:`402 Payment Required`:
+ The client must pay the KYC fee for the KYC process.
+ **This is currently not implemented, see #7365.**
+ :http:statuscode:`403 Forbidden`:
+ The provided hash does not match the payment target.
+ :http:statuscode:`404 Not found`:
+ The payment target is unknown.
+ :http:statuscode:`451 Unavailable for Legal Reasons`:
+ The transaction cannot be completed due to AML rules.
+ Thus, the operation is currently not stuck on KYC, but
+ on exchange staff performing their AML review. The user
+ should be told to wait and/or contact the exchange operator
+ if the situation persists.
+ The response will be a `AccountAmlBlocked` object.
+
+ **Details:**
+
+ .. ts:def:: AccountKycStatus
+
+ interface AccountKycStatus {
+
+ // Details about the KYC check that the user
+ // passed.
+ kyc_details: KycDetails;
+
+ // Current time of the exchange, used as part of
+ // what the exchange signs over.
+ now: Timestamp;
+
+ // EdDSA signature of the exchange affirming the account
+ // is KYC'ed, must be of purpose
+ // ``TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS``
+ // and over ``TALER_AccountSetupStatusSignaturePS``.
+ exchange_sig: EddsaSignature;
+
+ // public key used to create the signature.
+ exchange_pub: EddsaPublicKey;
+
+ // Current AML state for the target account. Non-zero
+ // values indicate that the transfer is blocked due to
+ // AML enforcement.
+ aml_status: Integer;
+
+ }
+
+ .. ts:def:: AccountKycRedirect
+
+ interface AccountKycRedirect {
+
+ // URL that the user should open in a browser to
+ // proceed with the KYC process.
+ kyc_url: string;
+
+ // Current AML state for the target account. Non-zero
+ // values indicate that the transfer is blocked due to
+ // AML enforcement.
+ aml_status: Integer;
+
+ }
+
+ .. ts:def:: AccountAmlBlocked
+
+ interface AccountAmlBlocked {
+
+ // Current AML state for the target account. Non-zero
+ // values indicate that the transfer is blocked due to
+ // AML enforcement.
+ aml_status: Integer;
+
+ }
+
+ .. ts:def:: KycDetails
+
+ // Object that specifies which KYC checks are satisfied.
+ interface KycDetails {
+
+ // Keys are the names of the check(s).
+ // The values are for now always empty objects.
+
+ }
+
+.. http:get:: /kyc-proof/$PROVIDER_SECTION?state=$H_PAYTO
+
+ Endpoint accessed from the user's browser at the *end* of a
+ KYC process, possibly providing the exchange with additional
+ credentials to obtain the results of the KYC process.
+ Specifically, the URL arguments should provide
+ information to the exchange that allows it to verify that the
+ user has completed the KYC process. The details depend on
+ the logic, which is selected by the "$PROVIDER_SECTION".
+
+ While this is a GET (and thus safe, and idempotent), the operation
+ may actually trigger significant changes in the exchange's state.
+ In particular, it may update the KYC status of a particular
+ payment target.
+
+ **Request:**
+
+ Details on the request depend on the specific KYC logic
+ that was used.
+
+ If the KYC plugin logic is OAuth 2.0, the query parameters are:
+
+ :query code=CODE: OAuth 2.0 code argument.
+ :query state=STATE: OAuth 2.0 state argument with the H_PAYTO.
+
+ .. note::
+
+ Depending on the OAuth variant used, additional
+ query parameters may need to be passed here.
+
+ **Response:**
+
+ Given that the response is returned to a user using a browser and **not** to
+ a Taler wallet, the response format is in human-readable HTML and not in
+ machine-readable JSON.
+
+ :http:statuscode:`302 Found`:
+ The KYC operation succeeded and the
+ payment target is now authorized to transact.
+ The browser is redirected to a human-readable
+ page configured by the exchange operator.
+ :http:statuscode:`401 Unauthorized`:
+ The provided authorization token is invalid.
+ :http:statuscode:`404 Not found`:
+ The payment target is unknown.
+ :http:statuscode:`502 Bad Gateway`:
+ The exchange received an invalid reply from the
+ legitimization service.
+ :http:statuscode:`504 Gateway Timeout`:
+ The exchange did not receive a reply from the legitimization
+ service within a reasonable time period.
+
+
+.. http:get:: /kyc-webhook/$PROVIDER_SECTION/*
+.. http:post:: /kyc-webhook/$PROVIDER_SECTION/*
+.. http:get:: /kyc-webhook/$LOGIC/*
+.. http:post:: /kyc-webhook/$LOGIC/*
+
+ All of the above endpoints can be used to update KYC status of a particular
+ payment target. They provide information to the KYC logic of the exchange
+ that allows it to verify that the user has completed the KYC process. May
+ be a GET or a POST request, depending on the specific "$LOGIC" and/or the
+ "$PROVIDER_SECTION".
+
+ **Request:**
+
+ Details on the request depend on the specific KYC logic
+ that was used.
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The operation succeeded.
+ :http:statuscode:`404 Not found`:
+ The specified logic is unknown.
+
+
+---------------
+Reserve control
+---------------
+
+This section describes the reserve control API which can be used to (1)
+prevent a reserve from expiring, to (2) pay an annual fee to allow a number of
+purses to be created for the respective reserve without paying a purse fee
+each time, to (3) obtain KYC information associated with a reserve to prove
+the identity of the person sending an invoice to the payer, and to (4) close a
+reserve before it would naturally expire and possibly (5) wire the funds to a
+designated account.
+
+ .. note::
+
+ This section is about a proposed API. It is not implemented. See also DD 31.
+
+.. http:post:: /reserves/$RESERVE_PUB/open
+
+ Request keeping a reserve open for invoicing.
+
+ **Request:**
+
+ The request body must be a `ReserveOpenRequest` object.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The exchange responds with a `ReserveOpenResponse` object.
+ :http:statuscode:`402 Payment Required`:
+ The exchange responds with a `ReserveOpenFailure` object when
+ the payment offered is insufficient for the requested operation.
+ :http:statuscode:`403 Forbidden`:
+ The *TALER_SIGNATURE_WALLET_RESERVE_OPEN* signature is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ The reserve key does not belong to a reserve known to the exchange.
+ :http:statuscode:`409 Conflict`:
+ The balance of the reserve or of a coin was insufficient.
+ Which case it is can be decided by looking at the error code
+ (``TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS`` or
+ ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY`` or
+ ``TALER_EC_EXCHANGE_OPEN_INSUFFICIENT_FUNDS``).
+ The specific fields of the response depend on the error code
+ and include the signatures (and what was signed over) proving the
+ conflict.
+ The response is `WithdrawError` object or a `DepositDoubleSpendError`
+ depending on the error type.
+ :http:statuscode:`451 Unavailable For Legal Reasons`:
+ This account has not yet passed the KYC checks.
+ The client must pass KYC checks before the reserve can be opened.
+ The response will be an `KycNeededRedirect` object.
+
+ **Details:**
+
+ .. ts:def:: ReserveOpenRequest
+
+ interface ReserveOpenRequest {
+ // Signature of purpose
+ // ``TALER_SIGNATURE_WALLET_RESERVE_OPEN`` over
+ // a `TALER_ReserveOpenPS`.
+ reserve_sig: EddsaSignature;
+
+ // Array of payments made towards the cost of the
+ // operation.
+ payments: OpenPaymentDetail[];
+
+ // Amount to be paid from the reserve for this
+ // operation.
+ reserve_payment: Amount;
+
+ // Time when the client made the request.
+ // Timestamp must be reasonably close to the time of
+ // the exchange, otherwise the exchange may reject
+ // the request (with a status code of 400).
+ request_timestamp: Timestamp;
+
+ // Desired new expiration time for the reserve.
+ // If the reserve would expire before this time,
+ // the exchange will charge account fees (and
+ // possibly KYC fees) until the expiration time
+ // exceeds this timestamp. Note that the exchange
+ // will refuse requests (with a status code of 400)
+ // if the time is so far in the future that the
+ // fees are not yet known (see /keys).
+ reserve_expiration: Timestamp;
+
+ // Desired open purse limit. Can be used to pay the
+ // annual account fee more than once to get a larger
+ // purse limit.
+ purse_limit: Integer;
+
+ }
+
+ .. ts:def:: ReserveOpenResponse
+
+ interface ReserveOpenResponse {
+ // Transaction cost for extending the expiration time.
+ // Excludes KYC fees.
+ open_cost: Amount;
+
+ // Current expiration time for the reserve.
+ reserve_expiration: Timestamp;
+ }
+
+ .. ts:def:: ReserveOpenFailure
+
+ interface ReserveOpenFailure {
+ // Transaction cost that should have been paid
+ // to extending the reserve as requested.
+ // Excludes KYC fees.
+ open_cost: Amount;
+
+ // Remaining expiration time for the reserve.
+ reserve_expiration: Timestamp;
+ }
+
+ .. ts:def:: OpenPaymentDetail
+
+ interface OpenPaymentDetail {
+
+ // Contribution of this coin to the overall amount.
+ // Can be a fraciton of the coin's total value.
+ amount: Amount;
+
+ // Hash of denomination RSA key with which the coin is signed.
+ denom_pub_hash: HashCode;
+
+ // Exchange's unblinded RSA signature of the coin.
+ ub_sig: DenominationSignature;
+
+ // Age commitment for the coin, if the denomination is age-restricted.
+ age_commitment?: AgeCommitment;
+
+ // Signature over `TALER_ReserveOpenDepositSignaturePS`
+ // of purpose ``TALER_SIGNATURE_WALLET_RESERVE_OPEN_DEPOSIT``
+ // made by the customer with the
+ // `coin's private key <coin-priv>`.
+ coin_sig: EddsaSignature;
+
+ // Public key of the coin being used to pay for
+ // opening the reserve.
+ coin_pub: EddsaPublicKey;
+
+ }
+
+
+.. http:get:: /reserves-attest/$RESERVE_PUB
+
+ Request list of available KYC attributes about the owner of a reserve.
+ Used as a preliminary step to find out which subsets of attributes the
+ exchange could provide signatures over.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The exchange responds with a `ReserveKycAttributes` object.
+ :http:statuscode:`404 Not found`:
+ The reserve key does not belong to a reserve known to the exchange.
+ :http:statuscode:`409 Conflict`:
+ The exchange does not have the requested KYC information.
+
+ **Details:**
+
+ .. ts:def:: ReserveKycAttributes
+
+ interface ReserveKycAttributes {
+ // Array of KYC attributes available. The attribute names
+ // listed are expected to be from the respective GANA
+ // registry.
+ details: string[];
+ }
+
+
+.. http:post:: /reserves-attest/$RESERVE_PUB
+
+ Request signed KYC information about the owner of a reserve.
+ This can be used by a reserve owner to include a proof
+ of their identity in invoices.
+
+ **Request:**
+
+ The request body must be a `ReserveAttestRequest` object.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The exchange responds with a `ReserveAttestResponse` object.
+ :http:statuscode:`403 Forbidden`:
+ The *TALER_SIGNATURE_WALLET_KYC_DETAILS* signature is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ The reserve key does not belong to a reserve known to the exchange.
+ :http:statuscode:`409 Conflict`:
+ The exchange does not have the requested KYC information.
+
+ **Details:**
+
+ .. ts:def:: ReserveAttestRequest
+
+ interface ReserveAttestRequest {
+ // Signature of purpose
+ // ``TALER_SIGNATURE_WALLET_ATTEST_DETAILS`` over
+ // a `TALER_WalletReserveAttestRequestSignaturePS`.
+ reserve_sig: EddsaSignature;
+
+ // Client's time for the request.
+ request_timestamp: Timestamp;
+
+ // Array of KYC attributes requested.
+ details: string[];
+ }
+
+ .. ts:def:: ReserveAttestResponse
+
+ interface ReserveAttestResponse {
+ // Signature of purpose
+ // ``TALER_SIGNATURE_EXCHANGE_RESERVE_ATTEST_DETAILS`` over
+ // a `TALER_ExchangeAttestPS`.
+ exchange_sig: EddsaSignature;
+
+ // Exchange public key used to create the
+ // signature.
+ exchange_pub: EddsaPublicKey;
+
+ // Time when the exchange created the signature.
+ exchange_timestamp: Timestamp;
+
+ // Expiration time for the provided information.
+ expiration_time: Timestamp;
+
+ // KYC details (key-value pairs) as requested.
+ // The keys will match the elements of the
+ // ``details`` array from the request.
+ attributes: Object;
+ }
+
+
+.. http:post:: /reserves/$RESERVE_PUB/close
+
+ Force immediate closure of a reserve. Does not actually
+ delete the reserve or the KYC data, but merely forces
+ the reserve's current balance to be wired back to the
+ account where it originated from, or another account of
+ the user's choosing if they performed the required KYC
+ check and designated another target account.
+
+ **Request:**
+
+ The request body must be a `ReserveCloseRequest` object.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The exchange responds with a `ReserveCloseResponse` object.
+ :http:statuscode:`403 Forbidden`:
+ The *TALER_SIGNATURE_WALLET_RESERVE_CLOSE* signature is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ The reserve key does not belong to a reserve known to the exchange.
+ :http:statuscode:`409 Conflict`:
+ No target account was given, and the exchange does not know an
+ origin account for this reserve.
+ :http:statuscode:`451 Unavailable For Legal Reasons`:
+ This account has not yet passed the KYC checks, hence wiring
+ funds to a non-origin account is not allowed.
+ The client must pass KYC checks before the reserve can be opened.
+ The response will be an `KycNeededRedirect` object.
+
+ **Details:**
+
+ .. ts:def:: ReserveCloseRequest
+
+ interface ReserveCloseRequest {
+ // Signature of purpose
+ // ``TALER_SIGNATURE_WALLET_RESERVE_CLOSE`` over
+ // a `TALER_ReserveCloseRequestSignaturePS`.
+ reserve_sig: EddsaSignature;
+
+ // Time when the client made the request.
+ // Timestamp must be reasonably close to the time of
+ // the exchange, otherwise the exchange may reject
+ // the request (with a status code of 400).
+ request_timestamp: Timestamp;
+
+ // payto://-URI of the account the reserve balance is to be
+ // wired to. Must be of the form: 'payto://$METHOD' for a
+ // wire method supported by this exchange (if the
+ // method is not supported, this is a bad request (400)).
+ // If not given, the reserve's origin account
+ // will be used. If no origin account is known for the
+ // reserve and not given, this is a conflict (409).
+ payto_uri?: string;
+
+ }
+
+ .. ts:def:: ReserveCloseResponse
+
+ interface ReserveCloseResponse {
+
+ // Actual amount that will be wired (excludes closing fee).
+ wire_amount: Amount;
+
+ }
+
+
+.. _delete-reserve:
+
+.. http:DELETE:: /reserves/$RESERVE_PUB
+
+ Forcefully closes a reserve.
+ The request header must contain an *Account-Request-Signature*.
+ Note: this endpoint is not currently implemented!
+
+ **Request:**
+
+ *Account-Request-Signature*: The client must provide Base-32 encoded EdDSA signature made with ``$ACCOUNT_PRIV``, affirming its authorization to delete the account. The purpose used MUST be ``TALER_SIGNATURE_RESERVE_CLOSE``.
+
+ :query force=BOOLEAN: *Optional.* If set to 'true' specified, the exchange
+ will delete the account even if there is a balance remaining.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The operation succeeded, the exchange provides details
+ about the account deletion.
+ The response will include a `ReserveDeletedResponse` object.
+ :http:statuscode:`403 Forbidden`:
+ The *Account-Request-Signature* is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ The account is unknown to the exchange.
+ :http:statuscode:`409 Conflict`:
+ The account is still has digital cash in it, the associated
+ wire method is ``void`` and the *force* option was not provided.
+ This response comes with a standard `ErrorDetail` response.
+
+ **Details:**
+
+ .. ts:def:: ReserveDeletedResponse
+
+ interface ReserveDeletedResponse {
+
+ // Final balance of the account.
+ closing_amount: Amount;
+
+ // Current time of the exchange, used as part of
+ // what the exchange signs over.
+ close_time: Timestamp;
+
+ // Hash of the wire account into which the remaining
+ // balance will be transferred. Note: may be the
+ // hash over ``payto://void/`, in which case the
+ // balance is forfeit to the profit of the exchange.
+ h_wire: HashCode;
+
+ // This is a signature over a
+ // struct ``TALER_AccountDeleteConfirmationPS`` with purpose
+ // ``TALER_SIGNATURE_EXCHANGE_RESERVE_DELETED``.
+ exchange_sig: EddsaSignature;
+
+ }
diff --git a/core/api-mailbox.rst b/core/api-mailbox.rst
new file mode 100644
index 00000000..34d27ded
--- /dev/null
+++ b/core/api-mailbox.rst
@@ -0,0 +1,215 @@
+..
+ This file is part of GNU TALER.
+ Copyright (C) 2022 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Christian Grothoff
+
+
+=======================
+The Mailbox RESTful API
+=======================
+
+This is a proposed API for the GNU Taler Mailbox service which allows Taler
+wallets to securely send push and pull payment requests to other wallets
+without having to interact with the respective messaging service.
+
+The API specified here follows the :ref:`general conventions <http-common>`
+for all details not specified in the individual requests.
+The `glossary <https://docs.taler.net/glossary.html#glossary>`_
+defines all specific terms used in this section.
+
+.. contents:: Table of Contents
+ :local:
+
+.. include:: tos.rst
+
+-------------------------
+Configuration information
+-------------------------
+
+.. http:get:: /config
+
+ Return the protocol version and currency supported by this service.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The body is a `VersionResponse`.
+
+ **Details:**
+
+ .. ts:def:: VersionResponse
+
+ interface VersionResponse {
+ // libtool-style representation of the Merchant protocol version, see
+ // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
+ // The format is "current:revision:age".
+ version: string;
+
+ // Name of the protocol.
+ name: "taler-mailbox";
+
+ // Fee per message.
+ message_fee: Amount;
+
+ // How long will the service store a message
+ // before giving up on delivery?
+ delivery_period: RelativeTime;
+
+ }
+
+----------------
+Sending messages
+----------------
+
+.. http:post:: /$H_MAILBOX
+
+ Puts a message into ``$H_MAILBOX``.
+ ``$H_MAILBOX`` is the SHA512 of an EdDSA public key.
+
+ **Request**
+
+ The body of the request must be an `IdentityMessage`.
+
+ **Response**
+
+ :http:statuscode:`204 No Content`
+ Message was stored and will be delivered.
+ :http:statuscode:`402 Payment Required`
+ Client needs to make a Taler payment before proceeding. See
+ standard Taler payment procedure.
+ :http:statuscode:`403 Forbidden`
+ The specified ``order_id`` does not permit sending
+ of this message. Possible reaons include the order
+ being for a different message, unpaid or
+ malformed.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`429 Too Many Requests`:
+ The system is currently experiencing a too high request
+ load and is unable to accept the message for delivery.
+ The response format is given by `MailboxRateLimitedResponse`_.
+
+ **Details:**
+
+ .. _IdentityMessage:
+ .. ts:def:: IdentityMessage
+
+ interface IdentityMessage {
+ // Public DH key used to encrypt the body. Must be fresh
+ // and only used once (ephemeral).
+ ephemeral_key: EcdhePublicKey;
+
+ // Encrypted message. Must be exactly 256-32 bytes long.
+ body: string;
+
+ // Order ID, if the client recently paid for this message.
+ order_id?: string;
+ }
+
+ .. _MailboxRateLimitedResponse:
+ .. ts:def:: MailboxRateLimitedResponse
+
+ interface MailboxRateLimitedResponse {
+
+ // Taler error code, TALER_EC_MAILBOX_DELIVERY_RATE_LIMITED.
+ code: number;
+
+ // When the client should retry.
+ retry_delay: RelativeTime;
+
+ // The human readable error message.
+ hint: string;
+
+ }
+
+------------------
+Receiving messages
+------------------
+
+.. http:get:: /$H_MAILBOX
+
+ Endpoint that returns unread messages in ``$H_MAILBOX``.
+ The number of messages returned by the service can be limited.
+ If the request is simply repeated, the same messages will be
+ returned again (or possibly more if additional messages arrived
+ and the total number is below the service's current internal limit).
+ To receive additional messages, the client generally has to first
+ explicitly DELETE already downloaded messages from the mailbox.
+
+ **Request:**
+
+ :query timeout_ms=NUMBER: *Optional.* If specified,
+ the Mailbox service will wait up to ``NUMBER``
+ milliseconds for the arrival of new messages
+ before sending the HTTP response. Note that if the
+ mailbox is non-empty, the service will always return
+ immediately with the messages in the mailbox, and not
+ wait for additional messages to arrive.
+
+ **Response**
+
+ :http:statuscode:`200 Ok`:
+ Messages are returned in binary format, 256 bytes per message,
+ starting with the ephemeral key and followed by
+ the encrypted body. Messages are not encapsulated in JSON!
+ :http:statuscode:`204 No Content`:
+ The mailbox is empty.
+ :http:statuscode:`429 Too Many Requests`:
+ The system is currently experiencing a too high request
+ load and is unable to accept the message for delivery.
+ The response format is given by `MailboxRateLimitedResponse`_.
+
+.. http:delete:: /$ADDRESS
+
+ Requests the deletion of already received messages from the
+ mailbox. Here, ``$ADDRESS`` must be the EdDSA public key
+ of the mailbox (not the hash!).
+
+ **Request**
+
+ The body of the request must be a ``MessageDeletionRequest``.
+
+ **Details:**
+
+ .. _MessageDeletionRequest:
+ .. ts:def:: MessageDeletionRequest
+
+ interface MessageDeletionRequest {
+
+ // Number of messages to delete. (Starting from the beginning
+ // of the latest GET response).
+ count: Integer;
+
+ // SHA-512 hash over all messages to delete.
+ checksum: HashCode;
+
+ // Signature by the mailbox's private key affirming
+ // the deletion of the messages, of purpuse
+ // ``TALER_SIGNATURE_WALLET_MAILBOX_DELETE_MESSAGES``.
+ wallet_sig: EddsaSignature;
+
+ }
+
+ **Response**
+
+ :http:statuscode:`204 No Content`:
+ Deletion complete.
+ :http:statuscode:`403 Forbidden`:
+ The ``wallet_sig`` is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ The checksum does not match the messages currently at the
+ head of the mailbox, or ``count`` is larger
+ than the number of messages currently in the mailbox.
+ This response comes with a standard `ErrorDetail` response.
diff --git a/core/api-merchant.rst b/core/api-merchant.rst
index bc68ef26..439e7177 100644
--- a/core/api-merchant.rst
+++ b/core/api-merchant.rst
@@ -1,6 +1,6 @@
..
This file is part of GNU TALER.
- Copyright (C) 2014-2020 Taler Systems SA
+ Copyright (C) 2014-2024 Taler Systems SA
TALER 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
@@ -16,14 +16,16 @@
@author Marcello Stanisci
@author Florian Dold
@author Christian Grothoff
+ @author Priscilla Huang
.. _merchant-api:
-====================
-Merchant Backend API
-====================
+============================
+Merchant Backend RESTful API
+============================
.. contents:: Table of Contents
+ :local:
-----------------------
Base URLs and Instances
@@ -34,11 +36,13 @@ This is useful when multiple businesses want to share the same payment
infrastructure.
Merchant backends have one special ``default`` instance. This ``default``
-instance is used when no explicit instance is specified. Despite its name,
-this instance must be created after the installation. In case *no* default
-instance is found - or its credentials got lost -, the administrator can use
-the default instance's rights by resorting on the ``--auth`` command line option,
-or by restarting the service by providing a environment variable called
+instance is used when no explicit instance is specified. Note that using
+``/instances/default/$ANYTHING`` is deprecated and will result in a permanent
+redirect (HTTP status 308) to ``$ANYTHING``. a Despite its name, this instance
+must be created after the installation. In case *no* default instance is
+found - or its credentials got lost -, the administrator can use the default
+instance's rights by resorting on the ``--auth`` command line option, or by
+restarting the service by providing an environment variable called
``TALER_MERCHANT_TOKEN``.
Each instance (default and others) has a base URL. The resources under
@@ -72,10 +76,10 @@ Examples:
https://merchant-backend.example.com/instances/myinst/orders/ABCD
A private endpoint (explicit "default" instance):
- https://merchant-backend.example.com/instances/default/private/orders
+ https://merchant-backend.example.com/private/orders
A public endpoint (explicit "default" instance):
- https://merchant-backend.example.com/instances/default/orders
+ https://merchant-backend.example.com/orders
Endpoints to manage other instances (ONLY for implicit "default" instance):
https://merchant-backend.example.com/management/instances
@@ -97,12 +101,17 @@ Authentication
Each merchant instance has separate authentication settings for the private API resources
of that instance.
-Currently, the API supports two auth methods:
+Currently, the API supports two main authentication methods:
* ``external``: With this method, no checks are done by the merchant backend.
Instead, a reverse proxy / API gateway must do all authentication/authorization checks.
* ``token``: With this method, the client must provide a ``Authorization: Bearer $TOKEN``
- header, where ``$TOKEN`` is a secret authentication token configured for the instance.
+ header, where ``$TOKEN`` is a secret authentication token configured for the instance which must begin with the RFC 8959 prefix.
+
+Additionally, clients can send a **login token** which they may obtain from
+the ``/private/token`` endpoint. Such a login token is valid only for a
+limited period of time and can be used by clients to avoid storing the
+long-term login secrets from an authentication method.
-----------------
Configuration API
@@ -114,11 +123,12 @@ such as the implemented version of the protocol and the currency used.
.. http:get:: /config
Return the protocol version and currency supported by this merchant backend.
+ This specification corresponds to ``current`` protocol being version **v14**.
**Response:**
:http:statuscode:`200 OK`:
- The exchange accepted all of the coins. The body is a `VersionResponse`.
+ The body is a `VersionResponse`.
.. ts:def:: VersionResponse
@@ -131,9 +141,53 @@ such as the implemented version of the protocol and the currency used.
// Name of the protocol.
name: "taler-merchant";
- // Currency supported by this backend.
+ // URN of the implementation (needed to interpret 'revision' in version).
+ // @since **v8**, may become mandatory in the future.
+ implementation?: string;
+
+ // Default (!) currency supported by this backend.
+ // This is the currency that the backend should
+ // suggest by default to the user when entering
+ // amounts. See ``currencies`` for a list of
+ // supported currencies and how to render them.
currency: string;
+ // How services should render currencies supported
+ // by this backend. Maps
+ // currency codes (e.g. "EUR" or "KUDOS") to
+ // the respective currency specification.
+ // All currencies in this map are supported by
+ // the backend. Note that the actual currency
+ // specifications are a *hint* for applications
+ // that would like *advice* on how to render amounts.
+ // Applications *may* ignore the currency specification
+ // if they know how to render currencies that they are
+ // used with.
+ currencies: { currency : CurrencySpecification};
+
+ // Array of exchanges trusted by the merchant.
+ // Since protocol **v6**.
+ exchanges: ExchangeConfigInfo[];
+
+ }
+
+ .. ts:def:: ExchangeConfigInfo
+
+ interface ExchangeConfigInfo {
+
+ // Base URL of the exchange REST API.
+ base_url: string;
+
+ // Currency for which the merchant is configured
+ // to trust the exchange.
+ // May not be the one the exchange actually uses,
+ // but is the only one we would trust this exchange for.
+ currency: string;
+
+ // Offline master public key of the exchange. The
+ // ``/keys`` data must be signed with this public
+ // key for us to trust it.
+ master_pub: EddsaPublicKey;
}
@@ -145,8 +199,7 @@ This section describes (public) endpoints that wallets must be able
to interact with directly (without HTTP-based authentication). These
endpoints are used to process payments (claiming an order, paying
for the order, checking payment/refund status and aborting payments),
-process refunds (checking refund status, obtaining the refund),
-and to pick up tips.
+and to process refunds (checking refund status, obtaining the refund).
Claiming an order
@@ -235,28 +288,34 @@ Making the payment
Either the client request is malformed or some specific processing error
happened that may be the fault of the client as detailed in the JSON body
of the response.
+ This includes the case where the payment is insufficient (sum is below
+ the required total amount, for example because the wallet calculated the
+ fees wrong).
:http:statuscode:`402 Payment required`:
There used to be a sufficient payment, but due to refunds the amount effectively
paid is no longer sufficient. (If the amount is generally insufficient, we
- return "406 Not Acceptable", only if this is because of refunds we return 402.)
+ return "400 Bad Request", only if this is because of refunds we return 402.)
:http:statuscode:`403 Forbidden`:
One of the coin signatures was not valid.
:http:statuscode:`404 Not found`:
The merchant backend could not find the order or the instance and thus cannot process the payment.
- :http:statuscode:`406 Not acceptable`:
- The payment is insufficient (sum is below the required total amount).
:http:statuscode:`408 Request timeout`:
The backend took too long to process the request. Likely the merchant's connection
to the exchange timed out. Try again.
:http:statuscode:`409 Conflict`:
- The exchange rejected the payment because a coin was already spent.
- The response will include the ``coin_pub`` for which the payment failed,
- in addition to the response from the exchange to the ``/deposit`` request.
+ The exchange rejected the payment because a coin was already spent (or
+ used in a different way for the same purchase previously), or
+ the merchant rejected the payment because the order was already fully paid
+ (and then return signatures with refunds). If a coin was already spent
+ (this includes re-using the same coin after a refund),
+ the response will include the ``exchange_url`` for which the payment failed,
+ in addition to the response from the exchange to the ``/batch-deposit`` request.
:http:statuscode:`410 Gone`:
The offer has expired and is no longer available.
:http:statuscode:`412 Precondition failed`:
The given exchange is not acceptable for this merchant, as it is not in the
list of accepted exchanges and not audited by an approved auditor.
+ TODO: Status code may be changed to 409 in the future as 412 is technically wrong.
:http:statuscode:`502 Bad gateway`:
The merchant's interaction with the exchange failed in some way.
The client might want to try again later.
@@ -279,6 +338,10 @@ Making the payment
// key of the merchant instance.
sig: EddsaSignature;
+ // Text to be shown to the point-of-sale staff as a proof of
+ // payment.
+ pos_confirmation?: string;
+
}
.. ts:def:: PayRequest
@@ -287,6 +350,23 @@ Making the payment
// The coins used to make the payment.
coins: CoinPaySig[];
+ // Index of the selected choice within the ``choices`` array of
+ // the contract terms.
+ // @since protocol **vSUBSCRIBE**
+ choice_index?: Integer;
+
+ // Input tokens required by choice indicated by ``choice_index``.
+ // @since protocol **vSUBSCRIBE**
+ tokens: TokenUseSig[];
+
+ // Array of output tokens to be (blindly) signed by the merchant.
+ // Output tokens specified in choice indicated by ``choice_index``.
+ // @since protocol **vSUBSCRIBE**
+ tokens_evs: TokenEnvelope[];
+
+ // Custom inputs from the wallet for the contract.
+ wallet_data?: Object;
+
// The session for which the payment is made (or replayed).
// Only set for session-based payments.
session_id?: string;
@@ -303,7 +383,7 @@ Making the payment
coin_pub: EddsaPublicKey;
// Signature made by the denomination public key.
- ub_sig: RsaSignature;
+ ub_sig: UnblindedSignature;
// The hash of the denomination public key associated with this coin.
h_denom: HashCode;
@@ -313,6 +393,78 @@ Making the payment
// URL of the exchange this coin was withdrawn from.
exchange_url: string;
+
+ // Signature affirming the posession of the
+ // respective private key proving that the payer
+ // is old enough. Only provided if the paid contract
+ // has an age restriction and the coin is
+ // age-restricted.
+ minimum_age_sig?: EddsaSignature;
+
+ // Age commitment vector of the coin.
+ // Only provided if the paid contract
+ // has an age restriction and the coin is
+ // age-restricted.
+ age_commitment?: Edx25519PublicKey[];
+
+ // Hash over the agge commitment vector of the coin.
+ // Only provided if the paid contract
+ // does NOT have an age restriction and the coin is
+ // age-restricted.
+ h_age_commitment?: AgeCommitmentHash;
+ }
+
+ .. ts:def:: TokenUseSig
+
+ interface TokenUseSig {
+
+ // Signature on ``TALER_DepositRequestPS`` with the public key of the
+ // token being provisioned to the merchant.
+ token_sig: EddsaSignature;
+
+ // Public key of the token being provisioned to the merchant.
+ token_pub: EddsaPublicKey;
+
+ // Unblinded signature made by the token family public key of the merchant.
+ ub_sig: UnblindedSignature;
+
+ // The hash of the token family public key associated with this token.
+ h_denom: HashCode;
+
+ }
+
+ .. ts:def:: TokenEnvelope
+
+ // This type depends on the cipher used to sign token families. This is
+ // configured by the merchant and defined for each token family in the
+ // contract terms.
+ type TokenEnvelope = RSATokenEnvelope | CSTokenEnvelope;
+
+ .. ts:def:: RSATokenEnvelope
+
+ interface RSATokenEnvelope {
+
+ // RSA is used for the blind signature.
+ cipher: "RSA";
+
+ // Blinded signature of the token's `public EdDSA key <eddsa-token-pub>`.
+ rsa_blinded_pub: BlindedRsaSignature;
+
+ }
+
+ .. ts:def:: CSTokenEnvelope
+
+ interface CSTokenEnvelope {
+ // Blind Clause-Schnorr signature scheme is used for the blind signature.
+ // See https://taler.net/papers/cs-thesis.pdf for details.
+ cipher: "CS";
+
+ // Public nonce
+ cs_nonce: string; // Crockford `Base32` encoded
+
+ // Two Curve25519 scalars, each representing a blinded challenge
+ cs_blinded_c0: string; // Crockford `Base32` encoded
+ cs_blinded_c1: string; // Crockford `Base32` encoded
}
Querying payment status
@@ -346,6 +498,7 @@ Querying payment status
merchant backend may return a response immediately.
:query await_refund_obtained=BOOLEAN: *Optional*. If set to "yes", poll for the order's pending refunds to be picked up. ``timeout_ms`` specifies how long we will wait for the refund.
:query refund=AMOUNT: *Optional*. Indicates that we are polling for a refund above the given AMOUNT. ``timeout_ms`` will specify how long we will wait for the refund.
+ :query allow_refunded_for_repurchase: *Optional*. Since protocol **v9** refunded orders are only returned under "already_paid_order_id" if this flag is set explicitly to "YES".
**Response:**
@@ -381,6 +534,9 @@ Querying payment status
// Amount that was refunded in total.
refund_amount: Amount;
+
+ // Amount that already taken by the wallet.
+ refund_taken: Amount;
}
.. ts:def:: StatusGotoResponse
@@ -442,10 +598,10 @@ again.
**Response:**
- :http:statuscode:`204 No content`:
+ :http:statuscode:`200 Ok`:
The merchant accepted the signature.
The ``frontend`` should now fulfill the contract.
- Note that it is possible that refunds have been granted.
+ Note that it is possible that refunds have been granted. Response is of type `PaidRefundStatusResponse`.
:http:statuscode:`400 Bad request`:
Either the client request is malformed or some specific processing error
happened that may be the fault of the client as detailed in the JSON body
@@ -456,6 +612,21 @@ again.
The merchant backend could not find the order or the instance
and thus cannot process the request.
+ **Details**:
+
+ .. ts:def:: PaidRefundStatusResponse
+
+ interface PaidRefundStatusResponse {
+
+ // Text to be shown to the point-of-sale staff as a proof of
+ // payment (present only if re-usable OTP algorithm is used).
+ pos_confirmation?: string;
+
+ // True if the order has been subjected to
+ // refunds. False if it was simply paid.
+ refunded: boolean;
+ }
+
.. ts:def:: PaidRequest
interface PaidRequest {
@@ -468,6 +639,9 @@ again.
// database access).
h_contract: HashCode;
+ // Hash over custom inputs from the wallet for the contract.
+ wallet_data_hash?: HashCode;
+
// Session id for which the payment is proven.
session_id: string;
}
@@ -504,7 +678,7 @@ are for incomplete payments for an order and never for established contracts.
:http:statuscode:`200 OK`:
The merchant accepted the request, and passed it on to the exchange. The body is a
- a `merchant refund response <MerchantRefundResponse>`. Note that the exchange
+ a `abort response <AbortResponse>`. Note that the exchange
MAY still have encountered errors in processing. Those will then be part of
the body. Wallets MUST carefully consider errors for each of the coins as
returned by the exchange.
@@ -704,6 +878,10 @@ the contract. Refunds must be approved by the merchant's business logic.
// Amount that was refunded, including refund fee charged by the exchange
// to the customer.
refund_amount: Amount;
+
+ // Timestamp when the merchant approved the refund.
+ // Useful for grouping refunds.
+ execution_time: Timestamp;
}
.. ts:def:: MerchantCoinRefundSuccessStatus
@@ -738,108 +916,10 @@ the contract. Refunds must be approved by the merchant's business logic.
// Amount that was refunded, including refund fee charged by the exchange
// to the customer.
refund_amount: Amount;
- }
-
-
-Picking up tips
----------------
-
-Tips are a way for wallets to obtain e-cash from
-a website.
-
-.. http:get:: [/instances/$INSTANCE]/tips/$TIP_ID
-
- Handle request from wallet to provide details about a tip.
-
- This endpoint typically also supports requests with the "Accept" header
- requesting "text/html". In this case, an HTML response suitable for
- triggering the interaction with the wallet is returned. If the backend
- installation does not include the required HTML templates, a 406 status
- code is returned.
-
- **Response:**
-
- :http:statuscode:`200 OK`:
- A tip is being returned. The backend responds with a `TipInformation`.
- :http:statuscode:`404 Not found`:
- The tip identifier is unknown.
- :http:statuscode:`406 Not acceptable`:
- The merchant backend could not load the template required to generate a reply in the desired format. (Likely HTML templates were not properly installed.)
- :http:statuscode:`410 Gone`:
- A tip has been fully claimed. The JSON reply still contains the `TipInformation`.
-
- .. ts:def:: TipInformation
-
- interface TipInformation {
-
- // Exchange from which the tip will be withdrawn. Needed by the
- // wallet to determine denominations, fees, etc.
- exchange_url: string;
-
- // (Remaining) amount of the tip (including fees).
- tip_amount: Amount;
-
- // Timestamp indicating when the tip is set to expire (may be in the past).
- // Note that tips that have expired MAY also result in a 404 response.
- expiration: Timestamp;
- }
-
-
-.. http:post:: [/instances/$INSTANCE]/tips/$TIP_ID/pickup
-
- Handle request from wallet to pick up a tip.
-
- **Request:**
-
- The request body is a `TipPickupRequest` object.
-
- **Response:**
-
- :http:statuscode:`200 OK`:
- A tip is being returned. The backend responds with a `TipResponse`.
- :http:statuscode:`401 Unauthorized`:
- The tip amount requested exceeds the tip.
- :http:statuscode:`404 Not found`:
- The tip identifier is unknown.
- :http:statuscode:`409 Conflict`:
- Some of the denomination key hashes of the request do not match those currently available from the exchange (hence there is a conflict between what the wallet requests and what the merchant believes the exchange can provide).
- :http:statuscode:`410 Gone`:
- The tip has expired.
-
- .. ts:def:: TipPickupRequest
-
- interface TipPickupRequest {
-
- // List of planchets the wallet wants to use for the tip.
- planchets: PlanchetDetail[];
- }
-
- .. ts:def:: PlanchetDetail
-
- interface PlanchetDetail {
- // Hash of the denomination's public key (hashed to reduce
- // bandwidth consumption).
- denom_pub_hash: HashCode;
-
- // Coin's blinded public key.
- coin_ev: CoinEnvelope;
- }
-
- .. ts:def:: TipResponse
- interface TipResponse {
-
- // Blind RSA signatures over the planchets.
- // The order of the signatures matches the planchets list.
- blind_sigs: BlindSignature[];
- }
-
- .. ts:def:: BlindSignature
-
- interface BlindSignature {
-
- // The (blind) RSA signature. Still needs to be unblinded.
- blind_sig: BlindedRsaSignature;
+ // Timestamp when the merchant approved the refund.
+ // Useful for grouping refunds.
+ execution_time: Timestamp;
}
@@ -848,7 +928,7 @@ Instance management
-------------------
Instances allow one merchant backend to be shared by multiple merchants.
-Every backend must have at least one instance, typcially the "default"
+Every backend must have at least one instance, typically the "default"
instance setup before it can be used to manage inventory or process payments.
@@ -879,13 +959,6 @@ Setting up instances
.. ts:def:: InstanceConfigurationMessage
interface InstanceConfigurationMessage {
- // The URI where the wallet will send coins. A merchant may have
- // multiple accounts, thus this is an array. Note that by
- // removing URIs from this list the respective account is set to
- // inactive and thus unavailable for new contracts, but preserved
- // in the database as existing offers and contracts may still refer
- // to it.
- payto_uris: string[];
// Name of the merchant instance to create (will become $INSTANCE).
// Must match the regex ``^[A-Za-z0-9][A-Za-z0-9_.@-]+$``.
@@ -894,6 +967,20 @@ Setting up instances
// Merchant name corresponding to this instance.
name: string;
+ // Type of the user (business or individual).
+ // Defaults to 'business'. Should become mandatory field
+ // in the future, left as optional for API compatibility for now.
+ user_type?: string;
+
+ // Merchant email for customer contact.
+ email?: string;
+
+ // Merchant public website.
+ website?: string;
+
+ // Merchant logo.
+ logo?: ImageDataUrl;
+
// Authentication settings for this instance
auth: InstanceAuthConfigurationMessage;
@@ -904,17 +991,10 @@ Setting up instances
// (to be put into contracts).
jurisdiction: Location;
- // Maximum wire fee this instance is willing to pay.
- // Can be overridden by the frontend on a per-order basis.
- default_max_wire_fee: Amount;
-
- // Default factor for wire fee amortization calculations.
- // Can be overridden by the frontend on a per-order basis.
- default_wire_fee_amortization: Integer;
-
- // Maximum deposit fee (sum over all coins) this instance is willing to pay.
- // Can be overridden by the frontend on a per-order basis.
- default_max_deposit_fee: Amount;
+ // Use STEFAN curves to determine default fees?
+ // If false, no fees are allowed by default.
+ // Can always be overridden by the frontend on a per-order basis.
+ use_stefan: boolean;
// If the frontend does NOT specify an execution date, how long should
// we tell the exchange to wait to aggregate transactions before
@@ -928,16 +1008,15 @@ Setting up instances
}
-
.. http:post:: /management/instances/$INSTANCE/auth
.. http:post:: [/instances/$INSTANCE]/private/auth
- Update the authentication settings for an instance. POST operations against
- an instance are authenticated by checking that an authorization is provided
- that matches either the credential required by the instance being modified
- OR the ``default`` instance, depending on the access path used.
+ Update the authentication settings for an instance. POST operations against
+ an instance are authenticated by checking that an authorization is provided
+ that matches either the credential required by the instance being modified
+ OR the ``default`` instance, depending on the access path used.
- **Request** the request must be an `InstanceAuthConfigurationMessage`.
+ **Request** the request must be an `InstanceAuthConfigurationMessage`.
:http:statuscode:`204 No content`:
The backend has successfully created the instance.
@@ -955,7 +1034,7 @@ Setting up instances
// See "token" for details.
method: "external" | "token";
- // For method "external", this field is mandatory.
+ // For method "token", this field is mandatory.
// The token MUST begin with the string "secret-token:".
// After the auth token has been set (with method "token"),
// the value must be provided in a "Authorization: Bearer $token"
@@ -964,6 +1043,62 @@ Setting up instances
}
+.. http:post:: [/instances/$INSTANCE]/private/token
+
+ **Request:**
+
+ The request must be a `LoginTokenRequest`.
+
+ **Response:**
+
+ :http:statuscode:`200 Ok`:
+ The backend is returning the access token in a
+ `LoginTokenSuccessResponse`.
+
+ **Details:**
+
+ .. ts:def:: LoginTokenRequest
+
+ interface LoginTokenRequest {
+ // Scope of the token (which kinds of operations it will allow)
+ scope: "readonly" | "write";
+
+ // Server may impose its own upper bound
+ // on the token validity duration
+ duration?: RelativeTime;
+
+ // Can this token be refreshed?
+ // Defaults to false.
+ refreshable?: boolean;
+ }
+
+ .. ts:def:: LoginTokenSuccessResponse
+
+ interface LoginTokenSuccessResponse {
+ // The login token that can be used to access resources
+ // that are in scope for some time. Must be prefixed
+ // with "Bearer " when used in the "Authorization" HTTP header.
+ // Will already begin with the RFC 8959 prefix.
+ token: string;
+
+ // Scope of the token (which kinds of operations it will allow)
+ scope: "readonly" | "write";
+
+ // Server may impose its own upper bound
+ // on the token validity duration
+ expiration: Timestamp;
+
+ // Can this token be refreshed?
+ refreshable: boolean;
+ }
+
+.. http:delete:: [/instances/$INSTANCE]/private/token
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The access token used to authorize this request was revoked.
+
.. http:patch:: /management/instances/$INSTANCE
.. http:patch:: [/instances/$INSTANCE]/private
@@ -989,15 +1124,24 @@ Setting up instances
.. ts:def:: InstanceReconfigurationMessage
interface InstanceReconfigurationMessage {
- // The URI where the wallet will send coins. A merchant may have
- // multiple accounts, thus this is an array. Note that removing
- // URIs from this list deactivates the specified accounts
- // (they will no longer be used for future contracts).
- payto_uris: string[];
// Merchant name corresponding to this instance.
name: string;
+ // Type of the user (business or individual).
+ // Defaults to 'business'. Should become mandatory field
+ // in the future, left as optional for API compatibility for now.
+ user_type?: string;
+
+ // Merchant email for customer contact.
+ email?: string;
+
+ // Merchant public website.
+ website?: string;
+
+ // Merchant logo.
+ logo?: ImageDataUrl;
+
// The merchant's physical address (to be put into contracts).
address: Location;
@@ -1005,17 +1149,10 @@ Setting up instances
// (to be put into contracts).
jurisdiction: Location;
- // Maximum wire fee this instance is willing to pay.
- // Can be overridden by the frontend on a per-order basis.
- default_max_wire_fee: Amount;
-
- // Default factor for wire fee amortization calculations.
- // Can be overridden by the frontend on a per-order basis.
- default_wire_fee_amortization: Integer;
-
- // Maximum deposit fee (sum over all coins) this instance is willing to pay.
- // Can be overridden by the frontend on a per-order basis.
- default_max_deposit_fee: Amount;
+ // Use STEFAN curves to determine default fees?
+ // If false, no fees are allowed by default.
+ // Can always be overridden by the frontend on a per-order basis.
+ use_stefan: boolean;
// If the frontend does NOT specify an execution date, how long should
// we tell the exchange to wait to aggregate transactions before
@@ -1063,6 +1200,15 @@ Inspecting instances
// Merchant name corresponding to this instance.
name: string;
+ // Type of the user ("business" or "individual").
+ user_type: string;
+
+ // Merchant public website.
+ website?: string;
+
+ // Merchant logo.
+ logo?: ImageDataUrl;
+
// Merchant instance this response is about ($INSTANCE).
id: string;
@@ -1096,13 +1242,22 @@ Inspecting instances
.. ts:def:: QueryInstancesResponse
interface QueryInstancesResponse {
- // The URI where the wallet will send coins. A merchant may have
- // multiple accounts, thus this is an array.
- accounts: MerchantAccount[];
// Merchant name corresponding to this instance.
name: string;
+ // Type of the user ("business" or "individual").
+ user_type: string;
+
+ // Merchant email for customer contact.
+ email?: string;
+
+ // Merchant public website.
+ website?: string;
+
+ // Merchant logo.
+ logo?: ImageDataUrl;
+
// Public key of the merchant/instance, in Crockford Base32 encoding.
merchant_pub: EddsaPublicKey;
@@ -1113,17 +1268,10 @@ Inspecting instances
// (to be put into contracts).
jurisdiction: Location;
- // Maximum wire fee this instance is willing to pay.
- // Can be overridden by the frontend on a per-order basis.
- default_max_wire_fee: Amount;
-
- // Default factor for wire fee amortization calculations.
- // Can be overridden by the frontend on a per-order basis.
- default_wire_fee_amortization: Integer;
-
- // Maximum deposit fee (sum over all coins) this instance is willing to pay.
- // Can be overridden by the frontend on a per-order basis.
- default_max_deposit_fee: Amount;
+ // Use STEFAN curves to determine default fees?
+ // If false, no fees are allowed by default.
+ // Can always be overridden by the frontend on a per-order basis.
+ use_stefan: boolean;
// If the frontend does NOT specify an execution date, how long should
// we tell the exchange to wait to aggregate transactions before
@@ -1138,29 +1286,11 @@ Inspecting instances
// Authentication configuration.
// Does not contain the token when token auth is configured.
auth: {
- type: "external" | "token";
+ method: "external" | "token";
};
}
- .. ts:def:: MerchantAccount
-
- interface MerchantAccount {
-
- // payto:// URI of the account.
- payto_uri: string;
-
- // Hash over the wire details (including over the salt).
- h_wire: HashCode;
-
- // Salt used to compute h_wire.
- salt: HashCode;
-
- // true if this account is active,
- // false if it is historic.
- active: boolean;
- }
-
Deleting instances
------------------
@@ -1199,6 +1329,299 @@ Deleting instances
The latter case only applies if ``purge`` was set.
+KYC status checks
+-----------------
+
+ .. note::
+
+ This is a draft API that is not yet implemented.
+
+
+.. http:GET:: /management/instances/$INSTANCE/kyc
+.. http:GET:: /instances/$INSTANCE/private/kyc
+
+ Check KYC status of a particular payment target.
+ Prompts the exchange to inquire with the bank
+ as to the KYC status of the respective account
+ and returns the result.
+
+ **Request:**
+
+ :query h_wire=H_WIRE: *Optional*. If specified, the KYC check should return the KYC status only for this wire account. Otherwise, for all wire accounts.
+ :query exchange_url=URL: *Optional*. If specified, the KYC check should return the KYC status only for the given exchange. Otherwise, for all exchanges we interacted with.
+ :query timeout_ms=NUMBER: *Optional.* If specified, the merchant will
+ wait up to ``timeout_ms`` milliseconds for the exchanges to confirm completion of the KYC process(es).
+
+ **Response:**
+
+ If different exchanges cause different errors when processing
+ the request, the largest HTTP status code that is applicable
+ is returned.
+
+ :http:statuscode:`202 Accepted`:
+ The user should be redirected to the provided locations to perform
+ the required KYC checks to open an account. Afterwards, the
+ request should be repeated.
+ The response will be an `AccountKycRedirects` object.
+ :http:statuscode:`204 No content`:
+ All KYC operations queried have succeeded. This may change in the
+ future, but there is no need to check again soon. It is suggested
+ to check again at a frequency of hours or days.
+ :http:statuscode:`502 Bad gateway`:
+ We failed to obtain a response from an exchange (about the KYC status).
+ The response will be an `AccountKycRedirects` object.
+ :http:statuscode:`503 Service unavailable`:
+ We do not know our KYC status as the exchange has not yet
+ returned the necessary details. This is not an actual failure:
+ this is expected to happen if for example a deposit was not yet aggregated
+ by the exchange and thus the exchange has not yet initiated
+ the KYC process. The client should simply try again later. It is
+ suggested to check again at a frequency of minutes to hours.
+ :http:statuscode:`504 Gateway Timeout`:
+ The merchant did not receive a confirmation from an exchange
+ within the specified time period. Used when long-polling for the
+ result.
+
+ **Details:**
+
+ .. ts:def:: AccountKycRedirects
+
+ interface AccountKycRedirects {
+
+ // Array of pending KYCs.
+ pending_kycs: MerchantAccountKycRedirect[];
+
+ // Array of exchanges with no reply.
+ timeout_kycs: ExchangeKycTimeout[];
+ }
+
+ .. ts:def:: MerchantAccountKycRedirect
+
+ interface MerchantAccountKycRedirect {
+
+ // URL that the user should open in a browser to
+ // proceed with the KYC process (as returned
+ // by the exchange's ``/kyc-check/`` endpoint).
+ // Optional, missing if the account is blocked
+ // due to AML and not due to KYC.
+ kyc_url?: string;
+
+ // AML status of the account.
+ aml_status: Integer;
+
+ // Base URL of the exchange this is about.
+ exchange_url: string;
+
+ // Our bank wire account this is about.
+ payto_uri: string;
+
+ }
+
+ .. ts:def:: ExchangeKycTimeout
+
+ interface ExchangeKycTimeout {
+
+ // Base URL of the exchange this is about.
+ exchange_url: string;
+
+ // Numeric `error code <error-codes>` indicating errors the exchange
+ // returned, or TALER_EC_INVALID for none.
+ exchange_code: number;
+
+ // HTTP status code returned by the exchange when we asked for
+ // information about the KYC status.
+ // 0 if there was no response at all.
+ exchange_http_status: number;
+
+ }
+
+
+-------------
+Bank Accounts
+-------------
+
+One or more bank accounts must be associated with an instance
+so that the instance can receive payments. Payments may be made
+into any of the active bank accounts of an instance.
+
+
+.. http:post:: [/instances/$INSTANCE]/private/accounts
+
+ This is used to add an account to an instance.
+
+ **Request:**
+
+ The request must have an `AccountAddDetails` body.
+
+ **Response:**
+
+ :http:statuscode:`200 Ok`:
+ Adding the account was successful, we return the salt selected by the backend and the resulting wire hash in an `AccountAddResponse`.
+ :http:statuscode:`404 Not found`:
+ The merchant instance is unknown or it is not in our data.
+ :http:statuscode:`409 Conflict`:
+ The provided information is inconsistent with the current state of the instance.
+ Usually this means we already have this account, but with conflicting credit facade information.
+ Inactive accounts can be reactivated using this method even if the
+ credit facade information differs from the previous state.
+
+ .. ts:def:: AccountAddDetails
+
+ interface AccountAddDetails {
+
+ // payto:// URI of the account.
+ payto_uri: string;
+
+ // URL from where the merchant can download information
+ // about incoming wire transfers to this account.
+ credit_facade_url?: string;
+
+ // Credentials to use when accessing the credit facade.
+ // Never returned on a GET (as this may be somewhat
+ // sensitive data). Can be set in POST
+ // or PATCH requests to update (or delete) credentials.
+ // To really delete credentials, set them to the type: "none".
+ credit_facade_credentials?: FacadeCredentials;
+
+ }
+
+ .. ts:def:: FacadeCredentials
+
+ type FacadeCredentials =
+ | NoFacadeCredentials
+ | BasicAuthFacadeCredentials;
+
+ .. ts:def:: NoFacadeCredentials
+
+ interface NoFacadeCredentials {
+ type: "none";
+ };
+
+ .. ts:def:: BasicAuthFacadeCredentials
+
+ interface BasicAuthFacadeCredentials {
+ type: "basic";
+
+ // Username to use to authenticate
+ username: string;
+
+ // Password to use to authenticate
+ password: string;
+ };
+
+ .. ts:def:: AccountAddResponse
+
+ interface AccountAddResponse {
+
+ // Hash over the wire details (including over the salt).
+ h_wire: HashCode;
+
+ // Salt used to compute h_wire.
+ salt: HashCode;
+
+ }
+
+
+.. http:patch:: [/instances/$INSTANCE]/private/accounts/$H_WIRE
+
+ This is used to update a bank account.
+
+ **Request:**
+
+ The request must be a `AccountPatchDetails`.
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The template has successfully modified.
+ :http:statuscode:`404 Not found`:
+ The template(ID) is unknown to the backend.
+
+ .. ts:def:: AccountPatchDetails
+
+ interface AccountPatchDetails {
+
+ // URL from where the merchant can download information
+ // about incoming wire transfers to this account.
+ credit_facade_url?: string;
+
+ // Credentials to use when accessing the credit facade.
+ // Never returned on a GET (as this may be somewhat
+ // sensitive data). Can be set in POST
+ // or PATCH requests to update (or delete) credentials.
+ // To really delete credentials, set them to the type: "none".
+ // If the argument is omitted, the old credentials
+ // are simply preserved.
+ credit_facade_credentials?: FacadeCredentials;
+ }
+
+
+.. http:get:: [/instances/$INSTANCE]/private/accounts
+
+ This is used to return the list of all the bank accounts
+ of an instance.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The backend has successfully returned all the accounts. Returns a `AccountsSummaryResponse`.
+ :http:statuscode:`404 Not found`:
+ The backend has does not know about the instance.
+
+ .. ts:def:: AccountsSummaryResponse
+
+ interface AccountsSummaryResponse {
+
+ // List of accounts that are known for the instance.
+ accounts: BankAccountEntry[];
+ }
+
+ .. ts:def:: BankAccountEntry
+
+ interface BankAccountEntry {
+
+ // payto:// URI of the account.
+ payto_uri: string;
+
+ // Hash over the wire details (including over the salt).
+ h_wire: HashCode;
+
+ // Salt used to compute h_wire.
+ salt: HashCode;
+
+ // URL from where the merchant can download information
+ // about incoming wire transfers to this account.
+ credit_facade_url?: string;
+
+ // true if this account is active,
+ // false if it is historic.
+ active: boolean;
+ }
+
+.. http:get:: [/instances/$INSTANCE]/private/accounts/$H_WIRE
+
+ This is used to obtain detailed information about a specific bank account.
+
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The backend has successfully returned the detailed information about a specific bank account.
+ Returns a `BankAccountEntry`.
+ :http:statuscode:`404 Not found`:
+ The bank account or instance is unknown to the backend.
+
+
+.. http:delete:: [/instances/$INSTANCE]/private/accounts/$H_WIRE
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The backend has successfully deactivated the account.
+ :http:statuscode:`404 Not found`:
+ The backend does not know the instance or the account.
+
+
--------------------
Inventory management
--------------------
@@ -1272,6 +1695,9 @@ Adding products to the inventory
// Identifies when we expect the next restocking to happen.
next_restock?: Timestamp;
+ // Minimum age buyer must have (in years). Default is 0.
+ minimum_age?: Integer;
+
}
@@ -1344,6 +1770,9 @@ Adding products to the inventory
// Identifies when we expect the next restocking to happen.
next_restock?: Timestamp;
+ // Minimum age buyer must have (in years). Default is 0.
+ minimum_age?: Integer;
+
}
Inspecting inventory
@@ -1353,6 +1782,11 @@ Inspecting inventory
This is used to return the list of all items in the inventory.
+ **Request:**
+
+ :query limit: *Optional*. At most return the given number of results. Negative for descending by row ID, positive for ascending by row ID. Default is ``20``. Since protocol **v12**.
+ :query offset: *Optional*. Starting ``product_serial_id`` for an iteration. Since protocol **v12**.
+
**Response:**
:http:statuscode:`200 OK`:
@@ -1376,6 +1810,8 @@ Inspecting inventory
// Product identifier, as found in the product.
product_id: string;
+ // ``product_serial_id`` of the product in the database.
+ product_serial: Integer;
}
@@ -1435,6 +1871,9 @@ Inspecting inventory
// Identifies when we expect the next restocking to happen.
next_restock?: Timestamp;
+ // Minimum age buyer must have (in years).
+ minimum_age?: Integer;
+
}
@@ -1559,6 +1998,7 @@ Creating orders
(2) The merchant instance is unknown (including possibly the instance
being not configured for new orders).
(3) The wire method specified is not supported by the backend.
+ (4) An OTP device ID was specified and is unknown.
Details in the error code.
NOTE: currently the client has no good way to find out which product
@@ -1588,6 +2028,11 @@ Creating orders
// to select among the various (active) wire methods supported by the instance.
payment_target?: string;
+ // The session for which the payment is made (or replayed).
+ // Only set for session-based payments.
+ // Since protocol **v6**.
+ session_id?: string;
+
// Specifies that some products are to be included in the
// order from the inventory. For these inventory management
// is performed (so the products must be in stock) and
@@ -1602,39 +2047,208 @@ Creating orders
// be used in case different UUIDs were used for different
// products (i.e. in case the user started with multiple
// shopping sessions that were combined during checkout).
- lock_uuids: string[];
+ lock_uuids?: string[];
// Should a token for claiming the order be generated?
// False can make sense if the ORDER_ID is sufficiently
// high entropy to prevent adversarial claims (like it is
// if the backend auto-generates one). Default is 'true'.
+ // Note: This is NOT related to tokens used for subscriptins or refunds.
create_token?: boolean;
+ // OTP device ID to associate with the order.
+ // This parameter is optional.
+ otp_id?: string;
}
+ The `Order` object represents the starting point for new `ContractTerms`.
+ After validating and sanatizing all inputs, the merchant backend will add
+ additional information to the order and create a new `ContractTerms` object
+ that will be stored in the database.
+
.. ts:def:: Order
- type Order : MinimalOrderDetail | ContractTerms;
+ interface Order {
+ // Total price for the transaction.
+ // The exchange will subtract deposit fees from that amount
+ // before transferring it to the merchant.
+ amount: Amount;
+
+ // Human-readable description of the whole purchase.
+ summary: string;
- The following fields must be specified in the ``order`` field of the request. Other fields from
- `ContractTerms` are optional, and will override the defaults in the merchant configuration.
+ // Map from IETF BCP 47 language tags to localized summaries.
+ summary_i18n?: { [lang_tag: string]: string };
- .. ts:def:: MinimalOrderDetail
+ // Unique, free-form identifier for the order.
+ // Must be unique within a merchant instance.
+ // For merchants that do not store proposals in their DB
+ // before the customer paid for them, the ``order_id`` can be used
+ // by the frontend to restore a proposal from the information
+ // encoded in it (such as a short product identifier and timestamp).
+ order_id?: string;
- interface MinimalOrderDetail {
- // Amount to be paid by the customer.
- amount: Amount;
+ // List of contract choices that the customer can select from.
+ // @since protocol **vSUBSCRIBE**
+ choices?: OrderChoice[];
- // Short summary of the order.
- summary: string;
+ // URL where the same contract could be ordered again (if
+ // available). Returned also at the public order endpoint
+ // for people other than the actual buyer (hence public,
+ // in case order IDs are guessable).
+ public_reorder_url?: string;
- // See documentation of fulfillment_url in ContractTerms.
+ // See documentation of ``fulfillment_url`` field in `ContractTerms`.
// Either fulfillment_url or fulfillment_message must be specified.
+ // When creating an order, the fulfillment URL can
+ // contain ``${ORDER_ID}`` which will be substituted with the
+ // order ID of the newly created order.
fulfillment_url?: string;
- // See documentation of fulfillment_message in ContractTerms.
- // Either fulfillment_url or fulfillment_message must be specified.
+ // See documentation of ``fulfillment_message`` in `ContractTerms`.
+ // Either ``fulfillment_url`` or ``fulfillment_message`` must be specified.
fulfillment_message?: string;
+
+ // Map from IETF BCP 47 language tags to localized fulfillment
+ // messages.
+ fulfillment_message_i18n?: { [lang_tag: string]: string };
+
+ // Maximum total deposit fee accepted by the merchant for this contract.
+ // Overrides defaults of the merchant instance.
+ max_fee?: Amount;
+
+ // List of products that are part of the purchase.
+ products?: Product[];
+
+ // Time when this contract was generated. If null, defaults to current
+ // time of merchant backend.
+ timestamp?: Timestamp;
+
+ // After this deadline has passed, no refunds will be accepted.
+ // Overrides deadline calculated from ``refund_delay`` in
+ // ``PostOrderRequest``.
+ refund_deadline?: Timestamp;
+
+ // After this deadline, the merchant won't accept payments for the contract.
+ // Overrides deadline calculated from default pay delay configured in
+ // merchant backend.
+ pay_deadline?: Timestamp;
+
+ // Transfer deadline for the exchange. Must be in the deposit permissions
+ // of coins used to pay for this order.
+ // Overrides deadline calculated from default wire transfer delay
+ // configured in merchant backend. Must be after refund deadline.
+ wire_transfer_deadline?: Timestamp;
+
+ // Base URL of the (public!) merchant backend API.
+ // Must be an absolute URL that ends with a slash.
+ // Defaults to the base URL this request was made to.
+ merchant_base_url?: string;
+
+ // Delivery location for (all!) products.
+ delivery_location?: Location;
+
+ // Time indicating when the order should be delivered.
+ // May be overwritten by individual products.
+ // Must be in the future.
+ delivery_date?: Timestamp;
+
+ // See documentation of ``auto_refund`` in ``ContractTerms``.
+ // Specifies for how long the wallet should try to get an
+ // automatic refund for the purchase.
+ auto_refund?: RelativeTime;
+
+ // Extra data that is only interpreted by the merchant frontend.
+ // Useful when the merchant needs to store extra information on a
+ // contract without storing it separately in their database.
+ // Must really be an Object (not a string, integer, float or array).
+ extra?: Object;
+
+ }
+
+
+The `OrderChoice` object describes a possible choice within an order. The
+choice is done by the wallet and consists of in- and outputs. In the example
+of buying an article, the merchant could present the customer with the choice
+to use a valid subscription token or pay using a gift voucher. Available since
+protocol **vSUBSCRIBE**.
+
+ .. ts:def:: OrderChoice
+
+ interface OrderChoice {
+ // Inputs that must be provided by the customer, if this choice is selected.
+ inputs: OrderInput[];
+
+ // Outputs provided by the merchant, if this choice is selected.
+ outputs: OrderOutput[];
+ }
+
+ .. ts:def:: OrderInput
+
+ // For now, only token inputs are supported.
+ type OrderInput = OrderInputToken;
+
+ .. ts:def:: OrderInputToken
+
+ interface OrderInputToken {
+
+ // Token input.
+ type: "token";
+
+ // Token family slug as configured in the merchant backend. Slug is unique
+ // across all configured tokens of a merchant.
+ token_family_slug: string;
+
+ // Start of the validity period of the token. Based on this, the merchant
+ // will select the relevant signing key. This value is rounded down
+ // according to the configured rounding duration in the token family.
+ valid_after: Timestamp;
+
+ // How many units of the input are required.
+ // Defaults to 1 if not specified. Output with count == 0 are ignored by
+ // the merchant backend.
+ count?: Integer;
+
+ }
+
+ .. ts:def:: OrderOutput
+
+ type OrderOutput = OrderOutputToken | OrderOutputTaxReceipt;
+
+ .. ts:def:: OrderOutputToken
+
+ interface OrderOutputToken {
+
+ // Token output.
+ type: "token";
+
+ // Token family slug as configured in the merchant backend. Slug is unique
+ // across all configured tokens of a merchant.
+ token_family_slug: string;
+
+ // Start of the validity period of the token. Based on this, the merchant
+ // will select the relevant signing key. This value is rounded down
+ // according to the configured rounding duration in the token family.
+ valid_after: Timestamp;
+
+ // How many units of the output are issued by the merchant.
+ // Defaults to 1 if not specified. Output with count == 0 are ignored by
+ // the merchant backend.
+ count?: Integer;
+
+ }
+
+ .. ts:def:: OrderOutputTaxReceipt
+
+ interface OrderOutputTaxReceipt {
+
+ // Tax receipt output.
+ type: "tax-receipt";
+
+ // Base URL of the donation authority that will
+ // issue the tax receipt.
+ donau_url: string;
+
}
The following `MinimalInventoryProduct` can be provided if the parts of the
@@ -1649,51 +2263,49 @@ Creating orders
the ``amount`` of the ``order``, so the frontend must already have calculated
the total price --- including the ``inventory_products``.
- .. ts:def:: MinimalInventoryProduct
-
- Note that if the frontend does give details beyond these,
- it will override those details (including price or taxes)
- that the backend would otherwise fill in via the inventory.
-
- interface MinimalInventoryProduct {
- // Which product is requested (here mandatory!).
- product_id: string;
+.. ts:def:: MinimalInventoryProduct
- // How many units of the product are requested.
- quantity: Integer;
- }
+ // Note that if the frontend does give details beyond these,
+ // it will override those details (including price or taxes)
+ // that the backend would otherwise fill in via the inventory.
+ interface MinimalInventoryProduct {
+ // Which product is requested (here mandatory!).
+ product_id: string;
+ // How many units of the product are requested.
+ quantity: Integer;
+ }
- .. ts:def:: PostOrderResponse
+.. ts:def:: PostOrderResponse
- interface PostOrderResponse {
- // Order ID of the response that was just created.
- order_id: string;
+ interface PostOrderResponse {
+ // Order ID of the response that was just created.
+ order_id: string;
- // Token that authorizes the wallet to claim the order.
- // Provided only if "create_token" was set to 'true'
- // in the request.
- token?: ClaimToken;
- }
+ // Token that authorizes the wallet to claim the order.
+ // Provided only if "create_token" was set to 'true'
+ // in the request.
+ token?: ClaimToken;
+ }
- .. ts:def:: OutOfStockResponse
+.. ts:def:: OutOfStockResponse
- interface OutOfStockResponse {
+ interface OutOfStockResponse {
- // Product ID of an out-of-stock item.
- product_id: string;
+ // Product ID of an out-of-stock item.
+ product_id: string;
- // Requested quantity.
- requested_quantity: Integer;
+ // Requested quantity.
+ requested_quantity: Integer;
- // Available quantity (must be below ``requested_quantity``).
- available_quantity: Integer;
+ // Available quantity (must be below ``requested_quantity``).
+ available_quantity: Integer;
- // When do we expect the product to be again in stock?
- // Optional, not given if unknown.
- restock_expected?: Timestamp;
- }
+ // When do we expect the product to be again in stock?
+ // Optional, not given if unknown.
+ restock_expected?: Timestamp;
+ }
Inspecting orders
@@ -1708,10 +2320,14 @@ Inspecting orders
:query paid: *Optional*. If set to yes, only return paid orders, if no only unpaid orders. Do not give (or use "all") to see all orders regardless of payment status.
:query refunded: *Optional*. If set to yes, only return refunded orders, if no only unrefunded orders. Do not give (or use "all") to see all orders regardless of refund status.
:query wired: *Optional*. If set to yes, only return wired orders, if no only orders with missing wire transfers. Do not give (or use "all") to see all orders regardless of wire transfer status.
- :query delta: *Optional*. takes value of the form ``N (-N)``, so that at most ``N`` values strictly older (younger) than ``start`` and ``date_ms`` are returned. Defaults to ``-20`` to return the last 20 entries (before ``start`` and/or ``date_ms``).
- :query date_ms: *Optional.* Non-negative date in milliseconds after the UNIX Epoc, see ``delta`` for its interpretation. If not specified, we default to the oldest or most recent entry, depending on ``delta``.
- :query start: *Optional*. Row number threshold, see ``delta`` for its interpretation. Defaults to ``INT64_MAX``, namely the biggest row id possible in the database.
+ :query delta: *Optional*. takes value of the form ``N (-N)``, so that at most ``N`` values strictly older (younger) than ``start`` and ``date_s`` are returned. Defaults to ``-20`` to return the last 20 entries (before ``start`` and/or ``date_s``). Deprecated in protocol **v12**. Use *limit* instead.
+ :query limit: *Optional*. At most return the given number of results. Negative for descending by row ID, positive for ascending by row ID. Default is ``20``. Since protocol **v12**.
+ :query date_s: *Optional.* Non-negative date in seconds after the UNIX Epoc, see ``delta`` for its interpretation. If not specified, we default to the oldest or most recent entry, depending on ``delta``.
+ :query start: *Optional*. Row number threshold, see ``delta`` for its interpretation. Defaults to ``INT64_MAX``, namely the biggest row id possible in the database. Deprecated in protocol **v12**. Use *offset* instead.
+ :query offset: *Optional*. Starting ``row_id`` for an iteration. Since protocol **v12**.
:query timeout_ms: *Optional*. Timeout in milliseconds to wait for additional orders if the answer would otherwise be negative (long polling). Only useful if delta is positive. Note that the merchant MAY still return a response that contains fewer than ``delta`` orders.
+ :query session_id: *Optional*. Since protocol **v6**. Filters by session ID.
+ :query fulfillment_url: *Optional*. Since protocol **v6**. Filters by fulfillment URL.
**Response:**
@@ -1768,8 +2384,9 @@ Inspecting orders
**Request:**
:query session_id: *Optional*. Session ID that the payment must be bound to. If not specified, the payment is not session-bound.
- :query transfer: *Optional*. If set to "YES", try to obtain the wire transfer status for this order from the exchange. Otherwise, the wire transfer status MAY be returned if it is available.
+ :query transfer: Deprecated in protocol **V6**. *Optional*. If set to "YES", try to obtain the wire transfer status for this order from the exchange. Otherwise, the wire transfer status MAY be returned if it is available.
:query timeout_ms: *Optional*. Timeout in milliseconds to wait for a payment if the answer would otherwise be negative (long polling).
+ :query allow_refunded_for_repurchase: *Optional*. Since protocol **v9** refunded orders are only returned under "already_paid_order_id" if this flag is set explicitly to "YES".
**Response:**
@@ -1826,12 +2443,22 @@ Inspecting orders
// Contract terms.
contract_terms: ContractTerms;
+ // Index of the selected choice within the ``choices`` array of
+ // ``contract terms``.
+ // @since protocol **vSUBSCRIBE**
+ choice_index?: Integer;
+
+ // If the order is paid, set to the last time when a payment
+ // was made to pay for this order. Since **v14**.
+ last_payment: Timestamp;
+
// The wire transfer status from the exchange for this order if
// available, otherwise empty array.
wire_details: TransactionWireTransfer[];
// Reports about trouble obtaining wire transfer details,
// empty array if no trouble were encountered.
+ // @deprecated in protocol **v6**.
wire_reports: TransactionWireReport[];
// The refund details for this order. One entry per
@@ -1894,6 +2521,9 @@ Inspecting orders
// Reason given for the refund.
reason: string;
+ // Set to true if a refund is still available for the wallet for this payment.
+ pending: boolean;
+
// When was the refund approved.
timestamp: Timestamp;
@@ -2103,35 +2733,12 @@ Informing the backend about incoming wire transfers
**Response:**
- :http:statuscode:`200 OK`:
- The wire transfer is known to the exchange, details about it follow in the body.
- The body of the response is a `MerchantTrackTransferResponse`.
- :http:statuscode:`202 Accepted`:
- The exchange provided conflicting information about the transfer. Namely,
- there is at least one deposit among the deposits aggregated by ``wtid``
- that accounts for a coin whose
- details don't match the details stored in merchant's database about the same keyed coin.
- The response body contains the `ExchangeConflictDetails`.
- This is indicative of a malicious exchange that claims one thing, but did
- something else. (With respect to the HTTP specficiation, it is not
- precisely that we did not act upon the request, more that the usual
- action of filing the transaction as 'finished' does not apply. In
- the future, this is a case where the backend actually should report
- the bad behavior to the auditor -- and then hope for the auditor to
- resolve it. So in that respect, 202 is the right status code as more
- work remains to be done for a final resolution.)
+ :http:statuscode:`204 No content`:
+ The wire transfer is now confirmed at the merchant.
:http:statuscode:`404 Not found`:
The instance or account are unknown to the exchange.
:http:statuscode:`409 Conflict`:
- The wire transfer identifier is already known to us, but for a different amount,
- wire method or exchange, or the amount reported by the exchange differs from
- the amount reported by the merchant.
- :http:statuscode:`502 Bad gateway`:
- The exchange returned an error when we asked it about the ``GET /transfer`` status
- for this wire transfer. Details of the exchange error are returned.
- :http:statuscode:`504 Gateway timeout`:
- The merchant's interaction with the exchange took too long.
- The client might want to try again later.
+ The wire transfer identifier is already known to us, but for a different amount.
**Details:**
@@ -2151,168 +2758,6 @@ Informing the backend about incoming wire transfers
exchange_url: string;
}
- .. ts:def:: MerchantTrackTransferResponse
-
- interface MerchantTrackTransferResponse {
- // Total amount transferred.
- total: Amount;
-
- // Applicable wire fee that was charged.
- wire_fee: Amount;
-
- // Time of the execution of the wire transfer by the exchange, according to the exchange.
- execution_time: Timestamp;
-
- // Details about the deposits.
- deposits_sums: MerchantTrackTransferDetail[];
- }
-
- .. ts:def:: MerchantTrackTransferDetail
-
- interface MerchantTrackTransferDetail {
- // Business activity associated with the wire transferred amount
- // ``deposit_value``.
- order_id: string;
-
- // The total amount the exchange paid back for ``order_id``.
- deposit_value: Amount;
-
- // Applicable fees for the deposit.
- deposit_fee: Amount;
- }
-
-
- .. ts:def:: ExchangeConflictDetails
-
- type ExchangeConflictDetails = WireFeeConflictDetails |
- TrackTransferConflictDetails;
-
-
- .. ts:def:: WireFeeConflictDetails
-
- // Note: this is not the full 'proof' of misbehavior, as
- // the bogus message from the exchange with a signature
- // over the 'different' wire fee is missing.
- //
- // This information is NOT provided by the current implementation,
- // because this would be quite expensive to generate and is
- // hardly needed _here_. Once we add automated reports for
- // the Taler auditor, we need to generate this data anyway
- // and should probably return it here as well.
- interface WireFeeConflictDetails {
- // Numerical `error code <error-codes>`:
- code: "TALER_EC_MERCHANT_PRIVATE_POST_TRANSFERS_BAD_WIRE_FEE";
-
- // Text describing the issue for humans.
- hint: string;
-
- // Wire fee (wrongly) charged by the exchange, breaking the
- // contract affirmed by the ``exchange_sig``.
- wire_fee: Amount;
-
- // Timestamp of the wire transfer.
- execution_time: Timestamp;
-
- // The expected wire fee (as signed by the exchange).
- expected_wire_fee: Amount;
-
- // Expected closing fee (needed to verify signature).
- expected_closing_fee: Amount;
-
- // Start date of the expected fee structure.
- start_date: Timestamp;
-
- // End date of the expected fee structure.
- end_date: Timestamp;
-
- // Signature of the exchange affirming the expected fee structure.
- master_sig: EddsaSignature;
-
- // Master public key of the exchange.
- master_pub: EddsaPublicKey;
- }
-
-
- .. ts:def:: TrackTransferConflictDetails
-
- interface TrackTransferConflictDetails {
- // Numerical `error code <error-codes>`.
- code: "TALER_EC_MERCHANT_PRIVATE_POST_TRANSFERS_CONFLICTING_REPORTS";
-
- // Text describing the issue for humans.
- hint: string;
-
- // Offset in the ``exchange_transfer`` where the
- // exchange's response fails to match the ``exchange_deposit_proof``.
- conflict_offset: number;
-
- // The response from the exchange which tells us when the
- // coin was returned to us, except that it does not match
- // the expected value of the coin.
- //
- // This field is NOT provided by the current implementation,
- // because this would be quite expensive to generate and is
- // hardly needed _here_. Once we add automated reports for
- // the Taler auditor, we need to generate this data anyway
- // and should probably return it here as well.
- exchange_transfer?: TrackTransferResponse;
-
- // Public key of the exchange used to sign the response to
- // our deposit request.
- deposit_exchange_pub: EddsaPublicKey;
-
- // Signature of the exchange signing the (conflicting) response.
- // Signs over a ``struct TALER_DepositConfirmationPS``.
- deposit_exchange_sig: EddsaSignature;
-
- // Hash of the merchant's bank account the wire transfer went to.
- h_wire: HashCode;
-
- // Hash of the contract terms with the conflicting deposit.
- h_contract_terms: HashCode;
-
- // At what time the exchange received the deposit. Needed
- // to verify the ``exchange_sig``.
- deposit_timestamp: Timestamp;
-
- // At what time the refund possibility expired (needed to verify ``exchange_sig``).
- refund_deadline: Timestamp;
-
- // Public key of the coin for which we have conflicting information.
- coin_pub: EddsaPublicKey;
-
- // Amount the exchange counted the coin for in the transfer.
- amount_with_fee: Amount;
-
- // Expected value of the coin.
- coin_value: Amount;
-
- // Expected deposit fee of the coin.
- coin_fee: Amount;
-
- // Expected deposit fee of the coin.
- deposit_fee: Amount;
-
- }
-
- .. ts:def:: TrackTransferProof
-
- interface TrackTransferProof {
- // Signature from the exchange made with purpose
- // ``TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT``.
- exchange_sig: EddsaSignature;
-
- // Public EdDSA key of the exchange that was used to generate the signature.
- // Should match one of the exchange's signing keys from ``/keys``. Again given
- // explicitly as the client might otherwise be confused by clock skew as to
- // which signing key was used.
- exchange_pub: EddsaSignature;
-
- // Hash of the wire details (identical for all deposits).
- // Needed to check the ``exchange_sig``
- h_wire: HashCode;
- }
-
Querying known wire transfers
-----------------------------
@@ -2401,7 +2846,7 @@ once we got a reply from the exchange.
.. http:delete:: [/instances/$INSTANCE]/private/transfers/$TID
- Here, the TID ist the 'transfer_serial_id' of the transfer
+ Here, the TID is the 'transfer_serial_id' of the transfer
to delete.
**Response:**
@@ -2414,413 +2859,1001 @@ once we got a reply from the exchange.
The transfer cannot be deleted anymore.
---------------------
-Backend: Giving tips
---------------------
+-----------
+OTP Devices
+-----------
-Tips are a way for websites to give small amounts of e-cash to visitors (for
-example as a financial reward for providing information or watching
-advertizements). Tips are non-contractual: neither merchant nor consumer
-have any contractual information about the other party as a result of the
-tip.
+OTP devices can be used to allow offline merchants
+to validate that a customer made a payment.
-Create reserve
---------------
+.. http:post:: [/instances/$INSTANCE]/private/otp-devices
+
+ This is used to associate an OTP device with an instance.
-Reserves are basically funds a merchant has provided
-to an exchange for a tipping campaign. Each reserve
-has a limited lifetime (say 2--4 weeks). Any funds
-not used to tip customers will automatically be wired
-back from the exchange to the originating account.
+ **Request:**
+
+ The request must be a `OtpDeviceAddDetails`.
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The creation of the template is successful.
+ :http:statuscode:`404 Not found`:
+ The merchant instance is unknown or it is not in our data.
+
+ .. ts:def:: OtpDeviceAddDetails
+
+ interface OtpDeviceAddDetails {
+
+ // Device ID to use.
+ otp_device_id: string;
+
+ // Human-readable description for the device.
+ otp_device_description: string;
+
+ // A key encoded with RFC 3548 Base32.
+ // IMPORTANT: This is not using the typical
+ // Taler base32-crockford encoding.
+ // Instead it uses the RFC 3548 encoding to
+ // be compatible with the TOTP standard.
+ otp_key: string;
+
+ // Algorithm for computing the POS confirmation.
+ // "NONE" or 0: No algorithm (no pos confirmation will be generated)
+ // "TOTP_WITHOUT_PRICE" or 1: Without amounts (typical OTP device)
+ // "TOTP_WITH_PRICE" or 2: With amounts (special-purpose OTP device)
+ // The "String" variants are supported @since protocol **v7**.
+ otp_algorithm: Integer | string;
-To begin tipping, a merchant must tell the backend
-to set up a reserve. The backend will return a
-reserve public key which must be used as the wire
-transfer subject when wiring the tipping campaign
-funds to the exchange.
+ // Counter for counter-based OTP devices.
+ otp_ctr?: Integer;
+ }
-.. _tips:
-.. http:post:: [/instances/$INSTANCE]/private/reserves
- Create a reserve for tipping.
+.. http:patch:: [/instances/$INSTANCE]/private/otp-devices/$DEVICE_ID
- This request is **not** idempotent. However, while repeating
- it will create another reserve, that is generally pretty harmless
- (assuming only one of the reserves is filled with a wire transfer).
- Clients may want to eventually delete the unused reserves to
- avoid clutter.
+ This is used to update an OTP device. It is useful when we need to change information in the OTP device or when we have mistake some information.
**Request:**
- The request body is a `ReserveCreateRequest` object.
+ The request must be a `OtpDevicePatchDetails`.
**Response:**
- :http:statuscode:`200 OK`:
- The backend is waiting for the reserve to be established. The merchant
- must now perform the wire transfer indicated in the `ReserveCreateConfirmation`.
- :http:statuscode:`408 Request timeout`:
- The exchange did not respond on time.
+ :http:statuscode:`204 No content`:
+ The template has successfully modified.
+ :http:statuscode:`404 Not found`:
+ The template(ID) is unknown to the backend.
:http:statuscode:`409 Conflict`:
- The exchange does not support the requested wire method.
- :http:statuscode:`502 Bad gateway`:
- We could not obtain ``/wire`` details from the specified exchange base URL.
- :http:statuscode:`504 Gateway timeout`:
- The merchant's interaction with the exchange took too long.
- The client might want to try again later.
+ The provided information is inconsistent with the current state of the template. Changes made is the same with
+ another store.
- .. ts:def:: ReserveCreateRequest
+ .. ts:def:: OtpDevicePatchDetails
- interface ReserveCreateRequest {
- // Amount that the merchant promises to put into the reserve.
- initial_balance: Amount;
+ interface OtpDevicePatchDetails {
- // Exchange the merchant intends to use for tipping.
- exchange_url: string;
+ // Human-readable description for the device.
+ otp_device_description: string;
- // Desired wire method, for example "iban" or "x-taler-bank".
- wire_method: string;
+ // A key encoded with RFC 3548 Base32.
+ // IMPORTANT: This is not using the typical
+ // Taler base32-crockford encoding.
+ // Instead it uses the RFC 3548 encoding to
+ // be compatible with the TOTP standard.
+ otp_key?: string;
+
+ // Algorithm for computing the POS confirmation.
+ otp_algorithm: Integer;
+
+ // Counter for counter-based OTP devices.
+ otp_ctr?: Integer;
+ }
+
+
+.. http:get:: [/instances/$INSTANCE]/private/otp-devices
+
+ This is used to return the list of all the OTP devices.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The backend has successfully returned all the templates. Returns a `OtpDeviceSummaryResponse`.
+ :http:statuscode:`404 Not found`:
+ The backend has does not know about the instance.
+
+ .. ts:def:: OtpDeviceSummaryResponse
+
+ interface OtpDeviceSummaryResponse {
+
+ // Array of devices that are present in our backend.
+ otp_devices: OtpDeviceEntry[];
}
- .. ts:def:: ReserveCreateConfirmation
+ .. ts:def:: OtpDeviceEntry
- interface ReserveCreateConfirmation {
- // Public key identifying the reserve.
- reserve_pub: EddsaPublicKey;
+ interface OtpDeviceEntry {
- // Wire account of the exchange where to transfer the funds.
- payto_uri: string;
+ // Device identifier.
+ otp_device_id: string;
+
+ // Human-readable description for the device.
+ device_description: string;
}
-.. http:get:: [/instances/$INSTANCE]/private/reserves
+.. http:get:: [/instances/$INSTANCE]/private/otp-devices/$DEVICE_ID
- Obtain list of reserves that have been created for tipping.
+ This is used to obtain detailed information about a specific OTP device.
- **Request:**
+ The client can provide additional inputs in the query to allow the backend
+ to compute and return a sample OTP code. Note that it is not an error if
+ the client provides query arguments that are not being used *or* that are
+ insufficient for the server to compute the ``otp_code``: If the client
+ provides inadequate query parameters, the ``otp_code`` is simply omitted
+ from the response.
+
+ **Query:**
- :query after: *Optional*. Only return reserves created after the given timestamp in milliseconds.
- :query active: *Optional*. Only return active/inactive reserves depending on the boolean given.
- :query failures: *Optional*. Only return reserves where we disagree with the exchange about the initial balance.
+ :query faketime=TIMESTAMP: *Optional*. Timestamp in seconds to use when calculating the current OTP code of the device. Since protocol **v10**.
+ :query price=AMOUNT: *Optional*. Price to use when calculating the current OTP code of the device. Since protocol **v10**.
**Response:**
:http:statuscode:`200 OK`:
- Returns a list of known tipping reserves.
- The body is a `TippingReserveStatus`.
+ The backend has successfully returned the detailed information about a specific OTP device.
+ Returns a `OtpDeviceDetails`.
+ :http:statuscode:`404 Not found`:
+ The OTP device or instance is unknown to the backend.
- .. ts:def:: TippingReserveStatus
+ .. ts:def:: OtpDeviceDetails
- interface TippingReserveStatus {
- // Array of all known reserves (possibly empty!).
- reserves: ReserveStatusEntry[];
- }
+ interface OtpDeviceDetails {
- .. ts:def:: ReserveStatusEntry
+ // Human-readable description for the device.
+ device_description: string;
- interface ReserveStatusEntry {
- // Public key of the reserve.
- reserve_pub: EddsaPublicKey;
+ // Algorithm for computing the POS confirmation.
+ //
+ // Currently, the following numbers are defined:
+ // 0: None
+ // 1: TOTP without price
+ // 2: TOTP with price
+ otp_algorithm: Integer;
+
+ // Counter for counter-based OTP devices.
+ otp_ctr?: Integer;
+
+ // Current time for time-based OTP devices.
+ // Will match the ``faketime`` argument of the
+ // query if one was present, otherwise the current
+ // time at the backend.
+ //
+ // Available since protocol **v10**.
+ otp_timestamp: Integer;
- // Timestamp when it was established.
- creation_time: Timestamp;
+ // Current OTP confirmation string of the device.
+ // Matches exactly the string that would be returned
+ // as part of a payment confirmation for the given
+ // amount and time (so may contain multiple OTP codes).
+ //
+ // If the ``otp_algorithm`` is time-based, the code is
+ // returned for the current time, or for the ``faketime``
+ // if a TIMESTAMP query argument was provided by the client.
+ //
+ // When using OTP with counters, the counter is **NOT**
+ // increased merely because this endpoint created
+ // an OTP code (this is a GET request, after all!).
+ //
+ // If the ``otp_algorithm`` requires an amount, the
+ // ``amount`` argument must be specified in the
+ // query, otherwise the ``otp_code`` is not
+ // generated.
+ //
+ // This field is *optional* in the response, as it is
+ // only provided if we could compute it based on the
+ // ``otp_algorithm`` and matching client query arguments.
+ //
+ // Available since protocol **v10**.
+ otp_code?: string;
- // Timestamp when it expires.
- expiration_time: Timestamp;
+ }
- // Initial amount as per reserve creation call.
- merchant_initial_amount: Amount;
+.. http:delete:: [/instances/$INSTANCE]/private/otp-devices/$DEVICE_ID
- // Initial amount as per exchange, 0 if exchange did
- // not confirm reserve creation yet.
- exchange_initial_amount: Amount;
+ **Response:**
- // Amount picked up so far.
- pickup_amount: Amount;
+ :http:statuscode:`204 No content`:
+ The backend has successfully deleted the OTP device.
+ :http:statuscode:`404 Not found`:
+ The backend does not know the instance or the OTP device.
+
+
+---------
+Templates
+---------
+
+The template is a backend feature that is used to allow wallets to create an
+order. This is useful in cases where a store does not have Internet
+connectivity or where a Web site wants to enable payments on a purely static
+Web page (for example to collect donations). In these cases, the GNU Taler
+wallet can be used to setup an order (and then of course pay for it).
+
+The template itself primarily provides order details that cannot be be changed
+by the customer when the wallet creates the order. The idea is that the user
+*may* be prompted to enter certain information, such as the amount to be paid,
+or the order summary (as a reminder to themselves or a message to the store),
+while the template provides all of the other contract details.
+
+The typical user-experience with templatates is that the user first scans a QR
+code or clicks on a taler://-URI which contains a ``pay-template`` (see `LSD
+0006 <https://lsd.gnunet.org/lsd0006/>`__). The URI specifies which values the
+user should supply, currently either nothing, the amount, the order summary or
+both. The URI may also specify defaults or partial defaults for those
+values. After the user has supplied those values, the wallet will use the
+public template API to create the order, then fetch the order details, and
+proceed as if it had been given the respective ``pay`` URI in the first place:
+show the full contract details and allow the user to make a payment. If the
+user chooses to aborts the payment, the wallet should give the user the
+opportunity to edit the values and create another order with different values.
+If the template does not include any values that the user is allowed to edit
+(so it is basically a fixed contract), the wallet should directly create the
+order and immediately proceed to the contract acceptance dialog.
+
+The business process for the templating API is also pretty simple. First, the
+private API is used to setup (or edit) the template, providing all of the
+contract terms that subsequently cannot be changed by the customer/wallet.
+This template data is then stored under the template ID which can be freely
+chosen. The SPA should also make it easy for the merchant to convert the
+template ID into a taler://-URI and/or QR code. Here, the merchant must
+additionally specify the defaults (if any) for the customer-editable values.
+Afterwards, the merchant can print out the QR code for display at the store,
+add a link to the taler://-URI and/or embed the respective QR-code image into
+their Web page.
+
+To receive a payment confirmation, the mechant may choose to configure a
+webhook in the merchant backend on the ``pay`` action, for example to send an
+SMS to their mobile phone. For points-of-sale without a mobile phone or
+Internet connectivity, the TBD mechanism can also be used to confirm payments.
+
+
+
+Adding templates
+----------------
- // Amount approved for tips that exceeds the pickup_amount.
- committed_amount: Amount;
+.. http:post:: [/instances/$INSTANCE]/private/templates
- // Is this reserve active (false if it was deleted but not purged)?
- active: boolean;
+ This is used to create a template.
+
+ **Request:**
+
+ The request must be a `TemplateAddDetails`.
+
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The creation of the template is successful.
+ :http:statuscode:`404 Not found`:
+ The merchant instance is unknown or it is not in our data.
+
+
+ .. ts:def:: TemplateAddDetails
+
+ interface TemplateAddDetails {
+
+ // Template ID to use.
+ template_id: string;
+
+ // Human-readable description for the template.
+ template_description: string;
+
+ // OTP device ID.
+ // This parameter is optional.
+ otp_id?: string;
+
+ // Fixed contract information for orders created from
+ // this template.
+ template_contract: TemplateContractDetails;
+
+ // Key-value pairs matching a subset of the
+ // fields from ``template_contract`` that are
+ // user-editable defaults for this template.
+ // Since protocol **v13**.
+ editable_defaults?: Object;
+
+ // Required currency for payments. Useful if no
+ // amount is specified in the ``template_contract``
+ // but the user should be required to pay in a
+ // particular currency anyway. Merchant backends
+ // may reject requests if the ``template_contract``
+ // or ``editable_defaults`` do
+ // specify an amount in a different currency.
+ // This parameter is optional.
+ // Since protocol **v13**.
+ required_currency?: string;
}
-Query funds remaining
----------------------
+ .. ts:def:: TemplateContractDetails
+
+ interface TemplateContractDetails {
-.. http:get:: [/instances/$INSTANCE]/private/reserves/$RESERVE_PUB
+ // Human-readable summary for the template.
+ summary?: string;
- Obtain information about a specific reserve that have been created for tipping.
+ // Required currency for payments to the template.
+ // The user may specify any amount, but it must be
+ // in this currency.
+ // This parameter is optional and should not be present
+ // if "amount" is given.
+ currency?: string;
+
+ // The price is imposed by the merchant and cannot be changed by the customer.
+ // This parameter is optional.
+ amount?: Amount;
+
+ // Minimum age buyer must have (in years). Default is 0.
+ minimum_age: Integer;
+
+ // The time the customer need to pay before his order will be deleted.
+ // It is deleted if the customer did not pay and if the duration is over.
+ pay_duration: RelativeTime;
+
+ }
+
+
+
+Editing templates
+-----------------
+
+
+.. http:patch:: [/instances/$INSTANCE]/private/templates/$TEMPLATE_ID
+
+ This is used to update a template. It is useful when we need to change information in the template or when we have mistake some information.
**Request:**
- :query tips: *Optional*. If set to "yes", returns also information about all of the tips created.
+ The request must be a `TemplatePatchDetails`.
**Response:**
- :http:statuscode:`200 OK`:
- Returns the `ReserveDetail`.
+ :http:statuscode:`204 No content`:
+ The template has successfully modified.
:http:statuscode:`404 Not found`:
- The tipping reserve is not known.
- :http:statuscode:`502 Bad gateway`:
- We are having trouble with the request because of a problem with the exchange.
- Likely returned with an "exchange_code" in addition to a "code" and
- an "exchange_http_status" in addition to our own HTTP status. Also usually
- includes the full exchange reply to our request under "exchange_reply".
- This is only returned if there was actual trouble with the exchange, not
- if the exchange merely did not respond yet or if it responded that the
- reserve was not yet filled.
- :http:statuscode:`504 Gateway timeout`:
- The merchant's interaction with the exchange took too long.
- The client might want to try again later.
+ The template(ID) is unknown to the backend.
+ :http:statuscode:`409 Conflict`:
+ The provided information is inconsistent with the current state of the template. Changes made is the same with
+ another store.
- .. ts:def:: ReserveDetail
- interface ReserveDetail {
- // Timestamp when it was established.
- creation_time: Timestamp;
+ .. ts:def:: TemplatePatchDetails
- // Timestamp when it expires.
- expiration_time: Timestamp;
+ interface TemplatePatchDetails {
- // Initial amount as per reserve creation call.
- merchant_initial_amount: Amount;
+ // Human-readable description for the template.
+ template_description: string;
- // Initial amount as per exchange, 0 if exchange did
- // not confirm reserve creation yet.
- exchange_initial_amount: Amount;
+ // OTP device ID.
+ // This parameter is optional.
+ otp_id?: string;
- // Amount picked up so far.
- pickup_amount: Amount;
+ // Additional information in a separate template.
+ template_contract: TemplateContractDetails;
- // Amount approved for tips that exceeds the pickup_amount.
- committed_amount: Amount;
+ // Key-value pairs matching a subset of the
+ // fields from ``template_contract`` that are
+ // user-editable defaults for this template.
+ // Since protocol **v13**.
+ editable_defaults?: Object;
- // Array of all tips created by this reserves (possibly empty!).
- // Only present if asked for explicitly.
- tips?: TipStatusEntry[];
+ // Required currency for payments. Useful if no
+ // amount is specified in the ``template_contract``
+ // but the user should be required to pay in a
+ // particular currency anyway. Merchant backends
+ // may reject requests if the ``template_contract``
+ // or ``editable_defaults`` do
+ // specify an amount in a different currency.
+ // This parameter is optional.
+ // Since protocol **v13**.
+ required_currency?: string;
+ }
- // Is this reserve active (false if it was deleted but not purged)?
- active: boolean;
- // URI to use to fill the reserve, can be NULL
- // if the reserve is inactive or was already filled
- payto_uri: string;
- // URL of the exchange hosting the reserve,
- // NULL if the reserve is inactive
- exchange_url: string;
- }
+Inspecting template
+-------------------
- .. ts:def:: TipStatusEntry
+.. http:get:: [/instances/$INSTANCE]/private/templates
- interface TipStatusEntry {
+ This is used to return the list of all the templates.
- // Unique identifier for the tip.
- tip_id: HashCode;
- // Total amount of the tip that can be withdrawn.
- total_amount: Amount;
+ **Response:**
- // Human-readable reason for why the tip was granted.
- reason: string;
+ :http:statuscode:`200 OK`:
+ The backend has successfully returned all the templates. Returns a `TemplateSummaryResponse`.
+ :http:statuscode:`404 Not found`:
+ The backend has does not know about the instance.
+
+ .. ts:def:: TemplateSummaryResponse
+
+ interface TemplateSummaryResponse {
+
+ // List of templates that are present in our backend.
+ templates: TemplateEntry[];
}
+ The `TemplateEntry` object describes a template. It has the following structure:
-Authorizing tips
-----------------
+ .. ts:def:: TemplateEntry
-.. http:post:: [/instances/$INSTANCE]/private/reserves/$RESERVE_PUB/authorize-tip
+ interface TemplateEntry {
- Authorize creation of a tip from the given reserve.
+ // Template identifier, as found in the template.
+ template_id: string;
- **Request:**
+ // Human-readable description for the template.
+ template_description: string;
+
+ }
+
+.. http:get:: [/instances/$INSTANCE]/private/templates/$TEMPLATE_ID
+
+ This is used to obtain detailed information about a specific template.
- The request body is a `TipCreateRequest` object.
**Response:**
:http:statuscode:`200 OK`:
- A tip has been created. The backend responds with a `TipCreateConfirmation`.
+ The backend has successfully returned the detailed information about a specific template.
+ Returns a `TemplateDetails`.
:http:statuscode:`404 Not found`:
- The instance or the reserve is unknown to the backend.
- :http:statuscode:`412 Precondition failed`:
- The tip amount requested exceeds the available reserve balance for tipping.
+ The instance or template(ID) is unknown to the backend.
- .. ts:def:: TipCreateRequest
- interface TipCreateRequest {
- // Amount that the customer should be tipped.
- amount: Amount;
+ .. ts:def:: TemplateDetails
+
+ interface TemplateDetails {
+
+ // Human-readable description for the template.
+ template_description: string;
+
+ // OTP device ID.
+ // This parameter is optional.
+ otp_id?: string;
- // Justification for giving the tip.
- justification: string;
+ // Additional information in a separate template.
+ template_contract: TemplateContractDetails;
- // URL that the user should be directed to after tipping,
- // will be included in the tip_token.
- next_url: string;
+ // Key-value pairs matching a subset of the
+ // fields from ``template_contract`` that are
+ // user-editable defaults for this template.
+ // Since protocol **v13**.
+ editable_defaults?: Object;
+
+ // Required currency for payments. Useful if no
+ // amount is specified in the ``template_contract``
+ // but the user should be required to pay in a
+ // particular currency anyway. Merchant backends
+ // may reject requests if the ``template_contract``
+ // or ``editable_defaults`` do
+ // specify an amount in a different currency.
+ // This parameter is optional.
+ // Since protocol **v13**.
+ required_currency?: string;
}
- .. ts:def:: TipCreateConfirmation
- interface TipCreateConfirmation {
- // Unique tip identifier for the tip that was created.
- tip_id: HashCode;
- // taler://tip URI for the tip.
- taler_tip_uri: string;
+Removing template
+-----------------
+
+.. http:delete:: [/instances/$INSTANCE]/private/templates/$TEMPLATE_ID
+
+ This is used to delete information about a template. If we no longer use it.
- // URL that will directly trigger processing
- // the tip when the browser is redirected to it.
- tip_status_url: string;
+ **Response:**
- // When does the tip expire?
- tip_expiration: Timestamp;
+ :http:statuscode:`204 No content`:
+ The backend has successfully deleted the template.
+ :http:statuscode:`404 Not found`:
+ The backend does not know the instance or the template.
+
+
+
+Using template
+--------------
+
+.. http:get:: [/instances/$INSTANCE]/templates/$TEMPLATE_ID
+
+ This is used to obtain information about a specific template by wallets
+ before they ask the user to fill in details.
+ This endpoint is available since protocol **v11**.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The backend has successfully returned the detailed information about a specific template.
+ Returns a `WalletTemplateDetails`.
+ :http:statuscode:`404 Not found`:
+ The instance or template(ID) is unknown to the backend.
+
+ .. ts:def:: WalletTemplateDetails
+
+ interface WalletTemplateDetails {
+
+ // Hard-coded information about the contrac terms
+ // for this template.
+ template_contract: TemplateContractDetails;
+
+ // Key-value pairs matching a subset of the
+ // fields from ``template_contract`` that are
+ // user-editable defaults for this template.
+ // Since protocol **v13**.
+ editable_defaults?: Object;
+
+ // Required currency for payments. Useful if no
+ // amount is specified in the ``template_contract``
+ // but the user should be required to pay in a
+ // particular currency anyway. Merchant backends
+ // may reject requests if the ``template_contract``
+ // or ``editable_defaults`` do
+ // specify an amount in a different currency.
+ // This parameter is optional.
+ // Since protocol **v13**.
+ required_currency?: string;
}
-.. http:post:: [/instances/$INSTANCE]/private/tips
+.. http:post:: [/instances/$INSTANCES]/templates/$TEMPLATE_ID
+
+ This using template can be modified by everyone and will be used to create order.
- Authorize creation of a tip from the given reserve, except with
- automatic selection of a working reserve of the instance by the
- backend. Intentionally otherwise identical to the ``/authorize-tip``
- endpoint given above.
**Request:**
- The request body is a `TipCreateRequest` object.
+ The request must be a `UsingTemplateDetails` and we accept JSON application and URL encoded.
+
**Response:**
- :http:statuscode:`200 OK`:
- A tip has been created. The backend responds with a `TipCreateConfirmation`.
+ The response is exactly the same type of response as when
+ creating an order using :ref:`POST /private/orders <post-order>`.
+
+ **Details:**
+
+ .. ts:def:: UsingTemplateDetails
+
+ interface UsingTemplateDetails {
+
+ // Summary of the template
+ summary?: string;
+
+ // The amount entered by the customer.
+ amount?: Amount;
+ }
+
+
+--------
+Webhooks
+--------
+
+The webhook is a backend feature that is used to send a confirmation to the merchant. It can be send with a SMS, email or with another method. It will confirm that the
+customer paid the merchant. It will show the date and the price the customer paid.
+
+
+
+Adding webhooks
+---------------
+
+.. http:post:: [/instances/$INSTANCES]/private/webhooks
+
+ This is used to create a webhook.
+
+ **Request:**
+
+ The request must be a `WebhookAddDetails`.
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The creation of the webhook is successsful.
+
:http:statuscode:`404 Not found`:
- The instance is unknown to the backend.
- :http:statuscode:`412 Precondition failed`:
- The tip amount requested exceeds the available reserve balance for tipping
- in all of the reserves of the instance.
+ The merchant instance is unknown or it not in our data.
+ .. ts:def:: WebhookAddDetails
-Deleting reserves
------------------
+ interface WebhookAddDetails {
+
+ // Webhook ID to use.
+ webhook_id: string;
+
+ // The event of the webhook: why the webhook is used.
+ event_type: string;
+
+ // URL of the webhook where the customer will be redirected.
+ url: string;
-.. http:delete:: [/instances/$INSTANCE]/private/reserves/$RESERVE_PUB
+ // Method used by the webhook
+ http_method: string;
- Delete information about a reserve. Fails if the reserve still has
- committed to tips that were not yet picked up and that have not yet
- expired.
+ // Header template of the webhook
+ header_template?: string;
+
+ // Body template by the webhook
+ body_template?: string;
+
+ }
+
+
+Editing webhooks
+----------------
+
+.. http:patch:: [/instances/$INSTANCES]/private/webhooks/$WEBHOOK_ID
+
+ This is used to update a webhook.
**Request:**
- :query purge: *Optional*. If set to YES, the reserve and all information
- about tips it issued will be fully deleted.
- Otherwise only the private key would be deleted.
+ The request must be a `WebhookPatchDetails`.
**Response:**
:http:statuscode:`204 No content`:
- The backend has successfully deleted the reserve.
+ The webhook has successfully modified.
:http:statuscode:`404 Not found`:
- The backend does not know the instance or the reserve.
+ The webhook(ID) is unknown to the backend.
:http:statuscode:`409 Conflict`:
- The backend refuses to delete the reserve (committed tips awaiting pickup).
+ The provided information is inconsistent with the current state of the webhook. Changes made is the same with another store.
+ .. ts:def:: WebhookPatchDetails
-Checking tip status
--------------------
+ interface WebhookPatchDetails {
-.. http:get:: [/instances/$INSTANCE]/private/tips/$TIP_ID
+ // The event of the webhook: why the webhook is used.
+ event_type: string;
- Obtain information about a particular tip.
+ // URL of the webhook where the customer will be redirected.
+ url: string;
- **Request:**
+ // Method used by the webhook
+ http_method: string;
+
+ // Header template of the webhook
+ header_template?: string;
+
+ // Body template by the webhook
+ body_template?: string;
+
+ }
+
+
+
+Inspecting webhook
+------------------
+
+.. http:get:: [/instances/$INSTANCES]/private/webhooks
- :query pickups: If set to "yes", returns also information about all of the pickups.
+ This is used to return all the webhooks that are present in our backend.
**Response:**
:http:statuscode:`200 OK`:
- The tip is known. The backend responds with a `TipDetails` message.
+ The backend has successfully returned all the webhooks. Returns a `WebhookSummaryResponse`.
+
:http:statuscode:`404 Not found`:
- The tip is unknown to the backend.
+ The backend has does not know about the instance.
- .. ts:def:: TipDetails
+ .. ts:def:: WebhookSummaryResponse
- interface TipDetails {
- // Amount that we authorized for this tip.
- total_authorized: Amount;
+ interface WebhookSummaryResponse {
- // Amount that was picked up by the user already.
- total_picked_up: Amount;
+ // Return webhooks that are present in our backend.
+ webhooks: WebhookEntry[];
- // Human-readable reason given when authorizing the tip.
- reason: string;
+ }
- // Timestamp indicating when the tip is set to expire (may be in the past).
- expiration: Timestamp;
+ The `WebhookEntry` object describes a webhook. It has the following structure:
- // Reserve public key from which the tip is funded.
- reserve_pub: EddsaPublicKey;
+ .. ts:def:: WebhookEntry
- // Array showing the pickup operations of the wallet (possibly empty!).
- // Only present if asked for explicitly.
- pickups?: PickupDetail[];
- }
+ interface WebhookEntry {
+
+ // Webhook identifier, as found in the webhook.
+ webhook_id: string;
+
+ // The event of the webhook: why the webhook is used.
+ event_type: string;
+
+ }
+
+
+.. http:get:: [/instances/$INSTANCES]/private/webhooks/$WEBHOOK_ID
+
+ This is used to obtain detailed information about apecific template.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The backend has successfully returned the detailed information about a specific webhook. Returns a `WebhookDetails`.
+
+ :http:statuscode:`404 Not found`:
+ The webhook(ID) is unknown to the backend.
+
+
+ .. ts:def:: WebhookDetails
+
+ interface WebhookDetails {
+
+ // The event of the webhook: why the webhook is used.
+ event_type: string;
+
+ // URL of the webhook where the customer will be redirected.
+ url: string;
+
+ // Method used by the webhook
+ http_method: string;
+
+ // Header template of the webhook
+ header_template?: string;
+
+ // Body template by the webhook
+ body_template?: string;
+
+ }
+
+
+Removing webhook
+-----------------
+
+.. http:delete:: [/instances/$INSTANCES]/private/webhooks/$WEBHOOK_ID
+
+ This is used to delete information about a webhook.
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The backend has successfully deleted the webhook.
+
+ :http:statuscode:`404 Not found`:
+ The webhook(ID) or the instance is unknown to the backend.
+
+
+
+----------------------------------------
+Token Families: Subscriptions, Discounts
+----------------------------------------
+
+This API provides functionalities for the issuance, management, and revocation
+of token families. Tokens facilitate the implementation of subscriptions and
+discounts, engaging solely the merchant and the user. Each token family
+encapsulates details pertaining to its respective tokens, guiding the merchant's
+backend on the appropriate processing and handling.
+
+
+Creating token families
+-----------------------
+
+.. http:post:: [/instances/$INSTANCES]/private/tokenfamilies
+
+ This is used to create a token family.
+
+ **Request:**
+
+ The request must be a `TokenFamilyCreateRequest`.
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The token family was created successfully.
+
+ :http:statuscode:`404 Not found`:
+ The merchant backend is unaware of the instance.
+
+ .. ts:def:: TokenFamilyCreateRequest
+
+ interface TokenFamilyCreateRequest {
+
+ // Identifier for the token family consisting of unreserved characters
+ // according to RFC 3986.
+ slug: string;
+
+ // Human-readable name for the token family.
+ name: string;
+
+ // Human-readable description for the token family.
+ description: string;
+
+ // Optional map from IETF BCP 47 language tags to localized descriptions.
+ description_i18n?: { [lang_tag: string]: string };
- .. ts:def:: PickupDetail
+ // Start time of the token family's validity period.
+ // If not specified, merchant backend will use the current time.
+ valid_after?: Timestamp;
- interface PickupDetail {
- // Unique identifier for the pickup operation.
- pickup_id: HashCode;
+ // End time of the token family's validity period.
+ valid_before: Timestamp;
- // Number of planchets involved.
- num_planchets: Integer;
+ // Validity duration of an issued token.
+ duration: RelativeTime;
+
+ // Kind of the token family.
+ kind: TokenFamilyKind;
+
+ }
- // Total amount requested for this pickup_id.
- requested_amount: Amount;
+ .. ts:def:: TokenFamilyKind
+
+ enum TokenFamilyKind {
+ Discount = "discount",
+ Subscription = "subscription",
}
-.. http:get:: [/instances/$INSTANCE]/private/tips
+Updating token families
+-----------------------
+
+.. http:patch:: [/instances/$INSTANCES]/private/tokenfamilies/$TOKEN_FAMILY_SLUG
- Return the list of all tips.
+ This is used to update a token family.
**Request:**
- :query include_expired: *Optional*. If set to "yes", the result includes expired tips also. Otherwise, only active tips are returned.
+ The request must be a `TokenFamilyUpdateRequest`.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The token family was successsful updated. Returns a `TokenFamilyDetails`.
+
+ :http:statuscode:`404 Not found`:
+ The merchant backend is unaware of the token family or instance.
+
+ .. ts:def:: TokenFamilyUpdateRequest
- :query limit: *Optional*. At most return the given number of results. Negative for descending in database row id, positive for ascending in database row id.
+ interface TokenFamilyUpdateRequest {
- :query offset: *Optional*. Starting ``row_id`` for an iteration.
+ // Human-readable name for the token family.
+ name: string;
+
+ // Human-readable description for the token family.
+ description: string;
+
+ // Optional map from IETF BCP 47 language tags to localized descriptions.
+ description_i18n: { [lang_tag: string]: string };
+
+ // Start time of the token family's validity period.
+ valid_after: Timestamp;
+
+ // End time of the token family's validity period.
+ valid_before: Timestamp;
+
+ // Validity duration of an issued token.
+ duration: RelativeTime;
+
+ }
+
+
+
+Inspecting token families
+-------------------------
+
+.. http:get:: [/instances/$INSTANCES]/private/tokenfamilies
+
+ This is used to list all configured token families for an instance.
**Response:**
:http:statuscode:`200 OK`:
- The backend has successfully found the list of tips. The backend responds
- with a `TipsResponse`.
+ The merchant backend has successfully returned all token families.
+ Returns a `TokenFamiliesList`.
- .. ts:def:: TipsResponse
+ :http:statuscode:`404 Not found`:
+ The merchant backend is unaware of the instance.
- interface TipsResponse {
+ .. ts:def:: TokenFamiliesList
- // List of tips that are present in the backend.
- tips: Tip[];
- }
+ // TODO: Add pagination
- .. ts:def:: Tip
+ interface TokenFamiliesList {
- interface Tip {
+ // All configured token families of this instance.
+ token_families: TokenFamilySummary[];
- // ID of the tip in the backend database.
- row_id: number;
+ }
- // Unique identifier for the tip.
- tip_id: HashCode;
+ .. ts:def:: TokenFamilySummary
- // (Remaining) amount of the tip (including fees).
- tip_amount: Amount;
- }
+ interface TokenFamilySummary {
+ // Identifier for the token family consisting of unreserved characters
+ // according to RFC 3986.
+ slug: string;
+
+ // Human-readable name for the token family.
+ name: string;
+
+ // Start time of the token family's validity period.
+ valid_after: Timestamp;
+
+ // End time of the token family's validity period.
+ valid_before: Timestamp;
+
+ // Kind of the token family.
+ kind: TokenFamilyKind;
+ }
+
+
+.. http:get:: [/instances/$INSTANCES]/private/tokenfamilies/$TOKEN_FAMILY_SLUG
+
+ This is used to get detailed information about a specific token family.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The merchant backend has successfully returned the detailed information
+ about a specific token family. Returns a `TokenFamilyDetails`.
+
+ :http:statuscode:`404 Not found`:
+ The merchant backend is unaware of the token family or instance.
+
+
+ The `TokenFamilyDetails` object describes a configured token family.
+
+ .. ts:def:: TokenFamilyDetails
+
+ interface TokenFamilyDetails {
+
+ // Identifier for the token family consisting of unreserved characters
+ // according to RFC 3986.
+ slug: string;
+
+ // Human-readable name for the token family.
+ name: string;
+
+ // Human-readable description for the token family.
+ description: string;
+
+ // Optional map from IETF BCP 47 language tags to localized descriptions.
+ description_i18n?: { [lang_tag: string]: string };
+
+ // Start time of the token family's validity period.
+ valid_after: Timestamp;
+
+ // End time of the token family's validity period.
+ valid_before: Timestamp;
+
+ // Validity duration of an issued token.
+ duration: RelativeTime;
+
+ // Kind of the token family.
+ kind: TokenFamilyKind;
+
+ // How many tokens have been issued for this family.
+ issued: Integer;
+
+ // How many tokens have been redeemed for this family.
+ redeemed: Integer;
+
+ }
+
+
+
+Deleting token families
+-----------------------
+
+.. http:delete:: [/instances/$INSTANCES]/private/tokenfamilies/$TOKEN_FAMILY_SLUG
+
+ This is used to delete a token family. Issued tokens of this family will not
+ be spendable anymore.
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The backend has successfully deleted the token family.
+
+ :http:statuscode:`404 Not found`:
+ The merchant backend is unaware of the token family or instance.
@@ -2853,6 +3886,10 @@ The contract terms must have the following structure:
// encoded in it (such as a short product identifier and timestamp).
order_id: string;
+ // List of contract choices that the customer can select from.
+ // @since protocol **vSUBSCRIBE**
+ choices: ContractChoice[];
+
// Total price for the transaction.
// The exchange will subtract deposit fees from that amount
// before transferring it to the merchant.
@@ -2865,13 +3902,26 @@ The contract terms must have the following structure:
public_reorder_url?: string;
// URL that will show that the order was successful after
- // it has been paid for. Optional. When POSTing to the
- // merchant, the placeholder "${ORDER_ID}" will be
- // replaced with the actual order ID (useful if the
+ // it has been paid for. Optional, but either ``fulfillment_url``
+ // or ``fulfillment_message`` must be specified in every
+ // contract terms.
+ //
+ // If a non-unique fulfillment URL is used, a customer can only
+ // buy the order once and will be redirected to a previous purchase
+ // when trying to buy an order with the same fulfillment URL a second
+ // time. This is useful for digital goods that a customer only needs
+ // to buy once but should be able to repeatedly download.
+ //
+ // For orders where the customer is expected to be able to make
+ // repeated purchases (for equivalent goods), the fulfillment URL
+ // should be made unique for every order. The easiest way to do
+ // this is to include a unique order ID in the fulfillment URL.
+ //
+ // When POSTing to the merchant, the placeholder text "${ORDER_ID}"
+ // is be replaced with the actual order ID (useful if the
// order ID is generated server-side and needs to be
- // in the URL).
- // Note that this placeholder can only be used once.
- // Either fulfillment_url or fulfillment_message must be specified.
+ // in the URL). Note that this placeholder can only be used once.
+ // Front-ends may use other means to generate a unique fulfillment URL.
fulfillment_url?: string;
// Message shown to the customer after paying for the order.
@@ -2883,23 +3933,9 @@ The contract terms must have the following structure:
fulfillment_message_i18n?: { [lang_tag: string]: string };
// Maximum total deposit fee accepted by the merchant for this contract.
+ // Overrides defaults of the merchant instance.
max_fee: Amount;
- // Maximum wire fee accepted by the merchant (customer share to be
- // divided by the ``wire_fee_amortization`` factor, and further reduced
- // if deposit fees are below ``max_fee``). Default if missing is zero.
- max_wire_fee: Amount;
-
- // Over how many customer transactions does the merchant expect to
- // amortize wire fees on average? If the exchange's wire fee is
- // above ``max_wire_fee``, the difference is divided by this number
- // to compute the expected customer's contribution to the wire fee.
- // The customer's contribution may further be reduced by the difference
- // between the ``max_fee`` and the sum of the actual deposit fees.
- // Optional, default value if missing is 1. 0 and negative values are
- // invalid and also interpreted as 1.
- wire_fee_amortization: number;
-
// List of products that are part of the purchase (see `Product`).
products: Product[];
@@ -2936,9 +3972,6 @@ The contract terms must have the following structure:
// The wire transfer fees must be added based on this wire transfer method.
wire_method: string;
- // Any exchanges audited by these auditors are accepted by the merchant.
- auditors: Auditor[];
-
// Exchanges that the merchant accepts even if it does not accept any auditors that audit them.
exchanges: Exchange[];
@@ -2975,10 +4008,19 @@ The contract terms must have the following structure:
// Extra data that is only interpreted by the merchant frontend.
// Useful when the merchant needs to store extra information on a
// contract without storing it separately in their database.
- extra?: any;
+ // Must really be an Object (not a string, integer, float or array).
+ extra?: Object;
+
+ // Minimum age the buyer must have (in years). Default is 0.
+ // This value is at least as large as the maximum over all
+ // mimimum age requirements of the products in this contract.
+ // It might also be set independent of any product, due to
+ // legal requirements.
+ minimum_age?: Integer;
+
}
-The wallet must select a exchange that either the merchant accepts directly by
+The wallet must select an exchange that either the merchant accepts directly by
listing it in the exchanges array, or for which the merchant accepts an auditor
that audits that exchange by listing it in the auditors array.
@@ -3033,6 +4075,15 @@ It has the following structure:
name: string;
// Label for a location with the business address of the merchant.
+ email?: string;
+
+ // Label for a location with the business address of the merchant.
+ website?: string;
+
+ // An optional base64-encoded product image.
+ logo?: ImageDataUrl;
+
+ // Label for a location with the business address of the merchant.
address?: Location;
// Label for a location that denotes the jurisdiction for disputes.
@@ -3097,6 +4148,18 @@ It has the following structure:
// The exchange's base URL.
url: string;
+ // How much would the merchant like to use this exchange.
+ // The wallet should use a suitable exchange with high
+ // priority. The following priority values are used, but
+ // it should be noted that they are NOT in any way normative.
+ //
+ // 0: likely it will not work (recently seen with account
+ // restriction that would be bad for this merchant)
+ // 512: merchant does not know, might be down (merchant
+ // did not yet get /wire response).
+ // 1024: good choice (recently confirmed working)
+ priority: Integer;
+
// Master public key of the exchange.
master_pub: EddsaPublicKey;
}
diff --git a/core/api-overview.rst b/core/api-overview.rst
new file mode 100644
index 00000000..7e32880a
--- /dev/null
+++ b/core/api-overview.rst
@@ -0,0 +1,150 @@
+..
+ This file is part of GNU TALER.
+ Copyright (C) 2014-2023 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero 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
+ @author Christian Grothoff
+
+========
+Overview
+========
+
+.. rubric:: Taler Exchange Public API
+
+* **Summary**: Public API for the payment service provider component of GNU Taler.
+* **Providers**: GNU Taler Exchange
+* **Consumers**: Wallet, Merchant
+* :doc:`Docs <api-exchange>`
+
+.. rubric:: Taler Exchange Management API
+
+* **Summary**: Management API for the payment service provider component of GNU Taler.
+* **Providers**: GNU Taler Exchange
+* **Consumers**: Exchange tooling (``taler-exchange-offline``), Auditor
+* :doc:`Docs <api-exchange>`
+
+.. rubric:: Taler Merchant Backend Public API
+
+* **Summary**: Allows communication between merchants and users' wallets.
+* **Providers**: GNU Taler Merchant backend
+* **Consumers**: Wallet
+* :doc:`Docs <api-merchant>`
+
+.. rubric:: Taler Merchant Backend Private API
+
+* **Summary**: Allows the merchant to manage Taler-based payments and related functionality.
+* **Providers**: GNU Taler Merchant backend
+* **Consumers**: Merchant's shop Website backend, Merchant PoS app, Merchant Backoffice UI
+* :doc:`Docs <api-merchant>`
+
+.. rubric:: Taler Wallet Core API
+
+* **Summary**: API to access functionality of the Taler Wallet service running locally on user's devices.
+* **Providers**: wallet-core
+* **Consumers**: UIs for the GNU Taler wallet
+
+.. rubric:: Core Bank API
+
+* **Summary**: Protocol to manage a simple core bank with optional regional
+ currency support. Allows access to a bank account by the owner of the
+ account. The owner can access the account balance, transaction list, and initate
+ payments.
+* **Providers**: LibEuFin bank, Taler Fakebank (partial)
+* **Consumers**: Cashier App, bank-ui
+* :doc:`Docs <api-corebank>`
+
+.. rubric:: Taler Bank Integration API
+
+* **Summary**: Offered by banks to provide the wallet/user with more information about ongoing withdrawals of Taler digital cash.
+* **Providers**: Taler fakebank, LibEuFin bank, Banks (that provide extra Taler support)
+* **Consumers**: Taler Wallet
+* :doc:`Docs <api-bank-integration>`
+
+.. rubric:: Taler Wire Gateway API
+
+* **Summary**: Allows the Taler Exchange to query incoming transactions and initiate payments with a protocol that abstracts away details of the underlying banking system.
+
+* **Providers**: Taler fakebank, LibEuFin Nexus, Depoloymerization wire gateway
+
+* **Consumers**: GNU Taler Exchange, Wire Auditor
+
+* :doc:`Docs <api-bank-wire>`
+
+.. rubric:: Taler Bank Revenue API
+
+* **Summary**: Offered by banks to provide clients the ability to download credit transaction histories.
+* **Providers**: Taler fakebank, LibEuFin bank, Banks (that provide extra Taler support)
+* **Consumers**: Taler Merchant, GNU Anastasis
+* :doc:`Docs <api-bank-revenue>`
+
+
+.. rubric:: Taler Sync API
+
+* **Summary**: Encrypted Data blob storage and retrieval API with payments for storage handled by GNU Taler payments.
+
+* **Providers**: GNU Taler Sync service
+
+* **Consumers**: Taler Wallet
+
+* :doc:`Docs <api-sync>`
+
+.. rubric:: Taler Auditor API
+
+* **Summary**: Reporting of certain transactions or potential problems directly to the auditor.
+* **Providers**: GNU Taler Auditor service
+* **Consumers**: GNU Taler Merchant, eventually Taler Wallet
+* :doc:`Docs <api-auditor>`
+
+.. rubric:: Taldir API
+
+* **Summary**: Looking up of Taler mailboxes associated with particular Internet service addresses.
+* **Providers**: GNU TalDir service
+* **Consumers**: GNU Taler Wallet
+* :doc:`Docs <api-taldir>`
+
+.. rubric:: Taler Mailbox API
+
+* **Summary**: Tansmission of encrypted payment messages between Taler wallets.
+* **Providers**: GNU Taler Mailbox service
+* **Consumers**: GNU Taler Wallet
+* :doc:`Docs <api-mailbox>`
+
+.. rubric:: Anastasis Provider Public API
+
+* **Summary**: Backup for secret splitting backup and recovery with GNU Anastasis providers.
+* **Providers**: GNU Anastasis providers
+* **Consumers**: Anastasis core client implementations (C implementation, TypeScript implementation)
+
+.. rubric:: Anastasis Reducer API
+
+* **Summary**: API used to step through the backup and recovery process of GNU Anastasis.
+* **Providers**: Anastasis core client implementations (C implementation, TypeScript implementation)
+* **Consumers**: Anastasis UIs (CLI, GTK, anastasis-webui)
+
+.. rubric:: LibEuFin Nexus API
+
+* **Summary**: API used to configure and access LibEuFin nexus, a generic server that supports multiple protocols to access a bank account.
+
+* **Providers**: LibEuFin Nexus service
+
+* **Consumers**: ``libeufin-cli``, (future) LibEuFin Web UI
+
+.. rubric:: EBICS
+
+* **Summary**: Allows businesses/banks/consumers to exchange data with a bank's core banking system.
+* **Consumers**: LibEuFin Nexus
+* **Providers**: libeufin-bank, Banks
diff --git a/core/api-sync.rst b/core/api-sync.rst
index 759a4c3f..c2c86c23 100644
--- a/core/api-sync.rst
+++ b/core/api-sync.rst
@@ -18,7 +18,7 @@
.. _sync-api:
======================================
-Backup and Synchronization Service API
+Backup and Synchronization RESTful API
======================================
The backup and synchronization service uses an EdDSA key
@@ -102,14 +102,20 @@ over TLS, and that the synchronization service is trusted to not build
user's location profiles by linking client IP addresses and client
keys.
+.. contents:: Table of Contents
+ :local:
---------------------------
-Receiving Terms of Service
---------------------------
+
+.. include:: tos.rst
+
+-----------------------
+Receiving Configuration
+-----------------------
.. http:get:: /config
- Obtain the terms of service provided by the storage service.
+ Obtain the key configuration settings of the storage service.
+ This specification corresponds to ``current`` protocol being version **2**.
**Response:**
@@ -135,11 +141,18 @@ Receiving Terms of Service
// The format is "current:revision:age".
version: string;
- }
+ // URN of the implementation (needed to interpret 'revision' in version).
+ // @since v2, may become mandatory in the future.
+ implementation?: string;
+ }
.. _sync:
+----------------------
+Recovering Backup Data
+----------------------
+
.. http:get:: /backups/${ACCOUNT-KEY}
Download latest version of the backup.
@@ -200,6 +213,10 @@ Receiving Terms of Service
signature validation.
+---------------------
+Uploading Backup Data
+---------------------
+
.. http:post:: /backups/${ACCOUNT-KEY}
Upload a new version of the account's database, or download the
diff --git a/core/api-taldir.rst b/core/api-taldir.rst
new file mode 100644
index 00000000..4da9bb02
--- /dev/null
+++ b/core/api-taldir.rst
@@ -0,0 +1,258 @@
+..
+ This file is part of GNU TALER.
+ Copyright (C) 2022 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Christian Grothoff
+ @author Martin Schanzenbach
+
+
+======================
+The TalDir RESTful API
+======================
+
+This is a proposed API for the TalDir service which allows Taler wallets to
+securely associate an inbox service (URL and public key) with the address of a
+messaging service used by the wallet's user. Wallets can also lookup the
+inbox of other users. This will enable wallets to make wallet-to-wallet
+payments to distant wallets where the target user is only identified by their
+address in a messaging service. Examples for messaging services include E-mail
+and SMS.
+
+The API specified here follows the :ref:`general conventions <http-common>`
+for all details not specified in the individual requests.
+The `glossary <https://docs.taler.net/glossary.html#glossary>`_
+defines all specific terms used in this section.
+
+.. contents:: Table of Contents
+ :local:
+
+.. include:: tos.rst
+
+
+-------------------------
+Configuration information
+-------------------------
+
+.. http:get:: /config
+
+ Return the protocol version and currency supported by this service.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The body is a `VersionResponse`.
+
+ .. ts:def:: VersionResponse
+
+ interface VersionResponse {
+ // libtool-style representation of the Merchant protocol version, see
+ // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
+ // The format is "current:revision:age".
+ version: string;
+
+ // Name of the protocol.
+ name: "taler-directory";
+
+ // Supported registration methods
+ methods: TaldirMethod[];
+
+ // fee for one month of registration
+ monthly_fee: Amount;
+
+ }
+
+ .. ts:def:: TaldirMethod
+
+ interface TaldirMethod {
+ // Name of the method, e.g. "email" or "sms".
+ name: string;
+
+ // per challenge fee
+ challenge_fee: Amount;
+
+ }
+
+--------------------
+Address registration
+--------------------
+
+.. http:post:: /register/$METHOD
+
+ Endpoint to register, extend or modify the registration for an address in
+ the directory.
+ Here, $METHOD is the type of address to register, e.g. "email", or "phone".
+ Supported methods are listed in the VersionResponse.
+ Note that duration should be given as a multiple of a month in microseconds.
+ If the duration is not a multiple of a month it will be rounded to the
+ nearest multiple. Halfway values will be rounded away from zero.
+ The cost calculation and resulting registration validity will be adjusted
+ automatically.
+ In order to only modify the data, the duration may be set to 0.
+ When the call is made with unmodified data and a duration of 0, the
+ endpoint will return how long this registration is currently paid for.
+
+ **Request**
+
+ .. ts:def:: IdentityMessage
+
+ interface IdentityMessage {
+ // Address, in $METHOD-specific format
+ address: string;
+
+ // Public key of the user to register. As string in Crockfor base32 encoding.
+ public_key: EddsaPublicKey;
+
+ // (HTTPS) endpoint URL for the inbox service.
+ inbox_url: string;
+
+ // For how long should the registration last/be extended.
+ duration: RelativeTime;
+
+ }
+
+ **Response**
+
+ :http:statuscode:`200 Ok`
+ Registration already exists for this address for the specified duration.
+ Returns for how long this registration is paid for.
+ The response format is given by `AlreadyPaidResponse`_.
+ :http:statuscode:`202 Accepted`
+ Registration was initiated, the client should check for receiving
+ a challenge at the address where registration was attempted.
+ :http:statuscode:`402 Payment Required`
+ Client needs to make a Taler payment before proceeding. See
+ standard Taler payment procedure.
+ :http:statuscode:`404 Not found`
+ The TalDir service does not support the specified method.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`429 Too Many Requests`:
+ The client exceeded the number of allowed attempts for initiating
+ a challenge for this address in the given timeframe.
+ The response format is given by `RateLimitedResponse`_.
+
+ .. _RateLimitedResponse:
+ .. ts:def:: RateLimitedResponse
+
+ interface RateLimitedResponse {
+
+ // Taler error code, TALER_EC_TALDIR_REGISTER_RATE_LIMITED.
+ code: number;
+
+ // At what frequency are new registrations allowed.
+ request_frequency: RelativeTime;
+
+ // The human readable error message.
+ hint: string;
+
+ }
+
+ .. _AlreadyPaidResponse:
+ .. ts:def:: AlreadyPaidResponse
+
+ interface AlreadyPaidResponse {
+
+ // The remaining duration for which this registration is still paid for
+ valid_for: RelativeTime;
+
+ }
+
+
+.. http:get:: /register/$H_ADDRESS/$PINTAN
+
+ Endpoint that generates an HTML Web site with a QR code and
+ ``taler://taldir/$H_ADDRESS/$PINTAN-wallet`` link for completing the
+ registration. Useful to open the registration challenge in a browser (say if
+ it was received on a different device than where the wallet is running).
+ Does NOT complete the registration, as some providers automatically click on
+ all links in messages. Yes, we do not like them doing so either, but ``GET``
+ is a "safe" method according to the HTTP standard, so technically this is
+ allowed.
+
+ Opening the link will lead the **wallet** to do the POST call below. If the
+ Taler wallet can somehow intercept the URL (say for SMS, if it has the right
+ permissions) it can skip this request and directly do the POST, as all of
+ the required new information is already encoded in the URL.
+
+ Note that the wallet must be involved before the POST is made, as the
+ wallet's public key from the registration must be hashed with the ``$PINTAN``
+ to protect the user against phishing. Otherwise, someone else might attempt
+ a concurrent registration of a different public key, and the user might
+ accidentally authorize the registration of the public key of a different
+ wallet.
+
+.. http:post:: /$H_ADDRESS
+
+ This request is the last step of a registration, proving to the TalDir that
+ the user of the wallet is indeed able to receive messages at the specified
+ address. ``$H_ADDRESS`` is the SHA-512 hash of the address to be registered in
+ Crockford base32 encoding.
+
+ **Request**
+
+ .. ts:def:: IdentityConfirmation
+
+ interface IdentityConfirmation {
+ // The solution is the SHA-512 hash of the challenge ($PINTAN) value
+ // chosen by TalDir (encoded as string just as given in the URL, but
+ // excluding the 0-termination) concatenated with the binary 32-byte
+ // value representing the wallet's EdDSA public key.
+ // The hash is provided as string in Crockford base32 encoding.
+ solution: HashCode;
+
+ }
+
+ **Response**
+
+ :http:statuscode:`204 No Content`:
+ Registration complete.
+ :http:statuscode:`403 Forbidden`:
+ The ``solution`` is invalid. Retrying immediately is allowed.
+ :http:statuscode:`404 Not found`:
+ The address is unknown (original registration attempt may have expired).
+ :http:statuscode:`429 Too Many Requests`:
+ The client exceeded the number of allowed attempts for solving
+ a challenge for this address in the given timeframe.
+
+--------------
+Address lookup
+--------------
+
+.. http:get:: /$H_ADDRESS
+
+ Lookup the public key (and mailbox service base URL) associated with
+ an address in the TalDir. Here, ``$H_ADDRESS`` is the SHA-512 hash of
+ a (presumably) registered address in Crockford base32 encoding.
+
+ **Response**
+
+ Standard HTTP cache control headers are used to specify how long the
+ registration is still expected to be valid.
+
+ :http:statuscode:`200 Ok`:
+ Registration information returned, of type `MailboxDetailResponse`
+ :http:statuscode:`404 Not found`:
+ The address is unknown (original registration may have expired).
+
+ .. _MailboxDetailResponse:
+ .. ts:def:: MailboxDetailResponse
+
+ interface MailboxDetailResponse {
+
+ // Registered public key of the user. As string in Crockford base32 encoding.
+ public_key: EddsaPublicKey;
+
+ // (HTTPS) endpoint URL for the inbox service.
+ inbox_url: string;
+
+ }
diff --git a/core/errors.rst b/core/errors.rst
deleted file mode 100644
index f7b490da..00000000
--- a/core/errors.rst
+++ /dev/null
@@ -1,79 +0,0 @@
-Errors and Testing
-##################
-
-This page lists errors that occur during the operation of GNU Taler.
-
-
-Error Conditions
-================
-
-``EXCHANGE_KEYS_INFO_UNAVAILABLE``
- An exchange does not return an HTTP 200 response for the ``/keys`` request.
-
-``EXCHANGE_KEYS_INFO_MALFORMED``
- The exchange returned an HTTP 200 response, but the body
- did not confirm the schema for ``/keys``.
-
-``EXCHANGE_KEYS_INFO_OUTDATED``
- The exchange returned a response for ``/keys`` with an issuing date
- earlier than the previous one.
-
- **Type**: Warning.
- **Handling**: The wallet should ignore the response and try again later.
-
-``EXCHANGE_WIRE_INFO_UNAVAILABLE``
- An exchange does not return an HTTP 200 response for the ``/wire`` request.
-
-``EXCHANGE_WIRE_INFO_MALFORMED``
- The exchange returned an HTTP 200 response, but the body
- did not confirm the schema for ``/wire``.
-
-``EXCHANGE_PROTOCOL_VERSION_UNSUPPORTED``
- An exchange's ``/keys`` response indicates a version number that
- is not compatible with the client.
-
-``EXCHANGE_MASTER_PUB_CHANGED``
- An exchange returns a ``/keys`` response with a master public key that differs
- from a previous response.
-
-``EXCHANGE_DENOM_MISSING``
- A denomination that has been previously offered by the exchange is not offered anymore,
- even though it hasn't expired yet.
-
-``EXCHANGE_DENOM_SIGNATURE_INVALID``
- The signature by the exchange's master key on a denomination is invalid.
-
-``EXCHANGE_DENOM_CHANGED``
- A denomination offered by the exchange is valid (syntax, content, signature),
- but has different information (fees, expiry) for the same public key compared
- to a previous keys response.
-
-``EXCHANGE_DENOM_CONTENT_INVALID``
- A denomination offered by the exchange is syntactically correct, but
- semantically malformed. For example, the expiration dates are not in the
- correct temporal order or the denomination public key can't be decoded.
-
-``EXCHANGE_WIRE_FEE_SIGNATURE_INVALID``
- The signature by the exchange's master key on a wire fee is invalid.
-
-``EXCHANGE_DENOMS_INADEQUATE``
- The denominations currently offered are inadequate for withdrawing digital cash.
- This can happen when all offered denominations are past their withdrawal expiry date.
-
-``EXCHANGE_RESERVE_STATUS_UNAVAILABLE``
-
-``WALLET_BUG``
- The wallet encountered a programming bug that should be reported to the developers.
-
- **Handling**: The wallet should allow the user to report this bug to the wallet developers.
-
-
-End-To-End Testing Scenarios
-============================
-
-This section describes some advanced end-to-end testing scenarios that should
-eventually be covered by our tests.
-
-* Reserve is created, closed, and then money is sent again to the reserve.
-
-* Amount from recoup should end up in customer's account again.
diff --git a/core/index-bank-apis.rst b/core/index-bank-apis.rst
new file mode 100644
index 00000000..f108df32
--- /dev/null
+++ b/core/index-bank-apis.rst
@@ -0,0 +1,38 @@
+..
+ This file is part of GNU TALER.
+ Copyright (C) 2014-2023 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero 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
+ @author Christian Grothoff
+
+=================
+Bank RESTful APIs
+=================
+
+
+.. toctree::
+ :maxdepth: 1
+
+ intro-bank-apis
+ api-corebank
+ api-bank-wire
+ api-bank-revenue
+ api-bank-integration
+ api-bank-conversion-info
+
+.. toctree::
+ :hidden:
diff --git a/core/index.rst b/core/index.rst
index 6dd762fd..8a764c10 100644
--- a/core/index.rst
+++ b/core/index.rst
@@ -1,6 +1,6 @@
..
This file is part of GNU TALER.
- Copyright (C) 2014-2020 Taler Systems SA
+ Copyright (C) 2014-2023 Taler Systems SA
TALER 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
@@ -23,22 +23,29 @@
Core Protocol Specification
---------------------------
-The *Protocol Specification* defines the HTTP-based, predominantly RESTful
-interfaces between the core components of Taler.
+This chapter describes the APIs used in the GNU Taler project. It includes
+both APIs that are pre-existing as well as APIs specific to the project.
+
+These *protocol specifications* define the interfaces between the core
+components of GNU Taler. Most of these interfaces use HTTP-based RESTful
+protocols using JSON.
+
.. toctree::
- :maxdepth: 2
+ :maxdepth: 1
+ api-overview
api-common
- api-error
api-exchange
api-merchant
+ ../wallet/wallet-core
api-auditor
api-sync
- api-wire
- api-bank-merchant
- api-bank-integration
- api-bank-access
- wireformats
- taler-uri
- errors
+ api-challenger
+ api-taldir
+ api-mailbox
+ index-bank-apis
+ api-donau
+
+.. toctree::
+ :hidden:
diff --git a/core/intro-bank-apis.rst b/core/intro-bank-apis.rst
new file mode 100644
index 00000000..f4307138
--- /dev/null
+++ b/core/intro-bank-apis.rst
@@ -0,0 +1,134 @@
+################################################
+Introduction to Taler (Core-)Banking Integration
+################################################
+
+This chapter provides an overview of the different ways that a bank or core
+banking system can provide integration with GNU Taler.
+
+
+Settlement Account Access
+#########################
+
+To make a GNU Taler deployment possible, the exchange service needs API access
+to a settlement bank account. The settlement account is used to fund digital
+cash withdrawals into users' Taler wallets, as well as to pay out merchants
+that deposited digital cash with the exchange.
+
+The following two operations need to be supported by the settlement account:
+
+1. Querying transactions on the settlement account.
+2. Initiating payments (simple credit transfer).
+
+Note that there is only **one** settlement account needed per Taler deployment.
+There is no per-user settlement account. Thus, creating or managing bank
+accounts is not a requirement.
+
+A core banking system could directly provide the HTTP/REST APIs
+consumed by the Taler exchange (:doc:`api-bank-integration`). Otherwise, an adapter (typically part
+of the libeufin component) needs to be written.
+
+
+Improved Withdrawal Process
+###########################
+
+In principle, any typical account-based (core-)banking system can be used as
+the underlying account-based financial layer for GNU Taler.
+
+However, without extra support from the bank, withdrawals can be difficult for
+unexperienced users. Thus to make sure that a Taler deployment can achieve
+mass adoption from non-technical users, extra integration by the bank / core
+banking system should be provided.
+
+Withdrawals without any extra support from the core banking system require the
+user to make a transaction to a particular bank account (i.e. the exchange's
+settlement account) with a rather long cryptographic identifier in the subject.
+This identifier is generated by the user's wallet when initiating a withdrawal
+from the wallet application. If the user misspells the identifier, the payment
+will be sent back automatically by the exchange.
+
+However, until the wire transfer is successfully completed, the wallet has no
+information about whether the transfer was already made by the user or if it
+was even made correctly. This makes it hard to show accurate information to
+the user about the status of withdrawing digital cash into their Taler wallet.
+
+
+Withdrawal Bank-Integration API
+===============================
+
+A core banking system can provide better support for GNU Taler withdrawals by
+allowing users to initiate *Taler withdrawal operations* from their bank
+account (e.g. in their banking app or online banking). A Taler withdrawal
+operation has a unique identifier (chosen/generated by the core banking
+system), called the WOPID (Withdrawal Operation Identifier).
+
+The core banking system can provide a (public) API to access withdrawal
+operations (:doc:`api-bank-integration`).
+
+The wallet learns the WOPID and API address via a ``taler://withdraw/...``
+QR-Code or link.
+
+The wallet generates the cryptographic identifiers required for the withdrawal,
+allows the user to choose an exchange (the bank may suggest a default one!),
+and then submits this information (chosen exchange, reserve public key) for the
+respective WOPID to the bank-integration API.
+
+The user can then confirm the withdrawal by completing the 2FA of
+their bank account for the operation. (Alternatively, the user can abort the operation
+in their banking client / 2FA app.)
+
+Upon completion of the 2FA / confirmation step, the core banking system
+initiates a credit transfer for the withdrawal operations (with the chosen
+exchange as the creditor and the cryptographic identifier / reserve pub in the
+subject). Afterwards, the withdrawal operation is marked as done.
+
+The wallet can continuously query the status of the withdrawal operation (via
+the API address and WOPID).
+In the Taler wallet app, the user can now always see the accurate status of
+their withdrawal operation (e.g. bank transfer done, aborted, confirmation/2FA
+pending).
+
+
+Payto-URI Integration
+=====================
+
+When initiating a withdrawal from the Taler wallet, the wallet can generate a
+payto:// link or QR code (see `RFC 8905 <https://www.rfc-editor.org/rfc/rfc8905.txt>`_)
+with the payment information necessary to make a
+credit transfer to the exchange's settlement account.
+
+Banking apps may provide integration here simply by handling payto:// URIs.
+
+Integration based on payto:// URIs prevents mistakes in typing the
+cryptographic identifier and bank account number during withdrawals. However,
+it still does not allow the wallet do accurately show the status of a
+withdrawal to the user.
+
+
+Future: Intent-Based Integration on Android
+===========================================
+
+(This type of integration is currently not specified, but planned for the future.)
+
+On the Android platform, applications can communicate via
+`Intents <https://developer.android.com/guide/components/intents-filters>`_.
+That would allow the Taler wallet to open a credit transfer dialog in a
+supported banking app to fund a withdrawal. The banking app can send the
+status of the credit transfer (confirmed/aborted by the user) back to the
+wallet, which can then show more accurate status information about the
+withdrawal to the user.
+
+
+Integration for Merchants
+#########################
+
+The Taler merchant backend has the option to connect to what
+we call the :doc:`Bank Revenue API <api-bank-revenue>`.
+
+A core banking system may provide this API to merchants that have a business
+account at the that bank. The API provides read-only access to incoming
+transactions on the merchant bank account.
+
+It allows merchants to easily and automatically reconcile incoming bank
+transfers from the Taler exchange's settlement account with the respective
+Taler payments. Usually multiple Taler payments are aggregated into one larger
+payment in the underlying banking layer.
diff --git a/core/taler-uri.rst b/core/taler-uri.rst
deleted file mode 100644
index dd45611e..00000000
--- a/core/taler-uri.rst
+++ /dev/null
@@ -1,149 +0,0 @@
-.. _taler-uri-scheme:
-
-=======================
-The taler:// URI scheme
-=======================
-
-The ``taler`` URI scheme represents actions that are processed by a Taler
-wallet. This document uses `RFC 6570 URI templates
-<https://tools.ietf.org/html/rfc6570>`__ to describe the syntax.
-
-The basic syntax is as follows:
-
-.. code:: none
-
- taler://{action}/{+rest}
-
-The alternative scheme name ``taler+http`` indicates that the referenced resource is to be accessed
-via plain HTTP instead of HTTPS. This **should** only be used for testing. A production
-version of the wallet **may** reject such URIs.
-
---------------------
-Requesting a Payment
---------------------
-
-Payments are requested with the ``pay`` action. The parameters are a hierarchical identifier for the requested payment:
-
-.. code:: none
-
- taler://pay/{merchant_host}{/merchant_prefix_path*}/{order_id}/{session_id}{?c}{#ssid}
-
-* ``merchant_host`` is the hostname (and optionally port) of the merchant.
-* ``merchant_prefix_path`` is an optional list of path components that identifies the path prefix of the merchant base URL.
-* ``order_id`` is the order ID that the customer is asked to pay for.
-* ``session_id`` is the optional session ID under which the payment takes place.
-* ``c`` is the optional high-entropy order `ClaimToken`.
-* ``ssid`` is the optional WLAN SSID that the merchant can offer the wallet to connect to for Internet connectivity.
-
-Examples:
-
-.. code:: none
-
- # Example 1:
- # Order ID "ORD123", no session ID.
- # Merchant backend base URL https://backend.test.taler.net/
- taler://pay/test.taler.net/ORD123/
-
- # Example 2:
- # Order ID "ORD123", no session ID.
- # Merchant backend base URL https://backend.test.taler.net/instances/x1/
- taler://pay/test.taler.net/instances/x1/ORD123/
-
- # Example 3:
- # Order ID "ORD123", session ID "ABC123".
- # Merchant backend base URL https://backend.test.taler.net/
- taler://pay/test.taler.net/ORD123/ABC123
-
- # INVALID Example 1:
- # When no session ID is given, the slash must still be present.
- taler://pay/test.taler.net/ORD123
-
-------------------------
-Withdrawing (Initiation)
-------------------------
-
-The action ``withdraw`` is used to trigger a bank-integrated withdrawal operation.
-
-.. code:: none
-
- taler://withdraw/{bank_host}{/bank_prefix_path*}/{withdrawal_uid}{#ssid}
-
-* ``bank_host`` is the hostname of the merchant.
-* ``bank_prefix_path`` is an optional list of path components that identifies the path prefix of the bank integration API base URL.
-* ``withdrawal_uid`` is the unique ID of the withdrawal operation.
-* ``ssid`` is the optional WLAN SSID that the bank (typically in an ATM scenario) can offer the wallet
- to connect to for Internet connectivity.
-
---------------------------
-Withdrawing (Confirmation)
---------------------------
-
-.. code:: none
-
- taler://notify-reserve/{reserve_pub}
-
-This action notifies the wallet that the status of a reserve has changed. It is used
-by the bank to indicate that the withdrawal has been confirmed by the user (e.g. via 2FA / mTAN / ...).
-The wallet then re-checks the status of all unconfirmed reserves.
-
-Optionally, ``reserve_pub`` can be specified to also indicate the reserve that
-has been updated.
-
-
----------
-Refunding
----------
-
-A ``taler://refund`` URI instructs the wallet to download and apply available refunds for an already paid order.
-
-.. code:: none
-
- taler://refund/{merchant_host}{/merchant_prefix_path*}/{order_id}/{#ssid}
- taler+http://refund/{merchant_host}{/merchant_prefix_path*}/{order_id}/{#ssid}
-
-* ``merchant_host`` is the hostname of the merchant.
-* ``merchant_prefix_path`` is an optional list of path components that identifies the path prefix of the merchant base URL.
-* ``order_id`` is the order ID to check for refunds.
-* ``ssid`` is the optional WLAN SSID that the merchant can offer the wallet to connect to for Internet connectivity.
-
-
--------
-Tipping
--------
-
-A tipping URI instructs the wallet to download information about a tip from
-a merchant and ask the user to accept/decline it.
-
-.. code:: none
-
- taler://tip/{merchant_host}{/merchant_prefix_path*}/{tip_id}/{#ssid}
-
-* ``merchant_host`` is the hostname of the merchant.
-* ``merchant_prefix_path`` is an optional list of path components that identifies the path prefix of the merchant base URL.
-* ``tip_id`` uniquely identifies the tip.
-* ``insecure`` is an optional query parameter. When "1", the ``merchant_host`` is contacted via HTTP.
- When absent or "0", the ``merchant_host`` is contacted via HTTPS.
-* ``ssid`` is the optional WLAN SSID that the merchant can offer the wallet to connect to for Internet connectivity.
-
-
-----------------
-Adding exchanges
-----------------
-
-A ``taler://exchange/`` URI instructs the wallet to display a prompt to the user, asking
-the user to confirm/decline adding the exchange to the list of trusted exchanges.
-
-.. code:: none
-
- taler://exchange/{exchange_host}{/exchange_prefix_path*}/
-
----------------
-Adding auditors
----------------
-
-A ``taler://auditor/`` URI instructs the wallet to display a prompt to the user, asking
-the user to confirm/decline adding the auditor to the list of trusted auditors.
-
-.. code:: none
-
- taler://auditor/{auditor_host}{/auditor_prefix_path*}/
diff --git a/core/tos.rst b/core/tos.rst
new file mode 100644
index 00000000..6c36be4c
--- /dev/null
+++ b/core/tos.rst
@@ -0,0 +1,43 @@
+--------------------
+Terms of service API
+--------------------
+
+These APIs allow clients to obtain the terms of service
+and the privacy policy of a service.
+
+
+.. http:get:: /terms
+
+ Get the terms of service of the service.
+ The endpoint will consider the "Accept" and "Accept-Language" and
+ "Accept-Encoding" headers when generating a response. Specifically,
+ it will try to find a response with an acceptable mime-type, then
+ pick the version in the most preferred language of the user, and
+ finally apply compression if that is allowed by the client and
+ deemed beneficial.
+
+ The endpoint will set an "Etag", and subsequent requests of the same client
+ should provide the tag in an "If-None-Match" header to detect if the terms
+ of service have changed. If not, a "304 Not Modified" response will be
+ returned. Note that the "304 Not Modified" will also be returned if the
+ client changed the "Accept-Language" or "Accept-Encoding" header. Thus, if
+ the client would like to download the resource in a different language or
+ format, the "If-None-Match" header must be omitted.
+
+ If the "Etag" is missing, the client should not cache the response and
+ instead prompt the user again at the next opportunity. This is usually only
+ the case if the terms of service were not configured correctly.
+
+ When returning a full response (not a "304 Not Modified"), the server
+ should also include a "Avail-Languages" header which includes
+ a comma-separated list of the languages in which the terms of service
+ are available in (see `availability hints specification
+ <https://datatracker.ietf.org/doc/draft-nottingham-http-availability-hints/>`_). Clients can use this to generate a language switcher
+ for users that may not have expressed a proper language preference.
+
+
+.. http:get:: /privacy
+
+ Get the privacy policy of the service. Behaves the same way as
+ The "/terms" endpoint, except that it returns the privacy policy
+ instead of the terms of service.
diff --git a/core/wireformats.rst b/core/wireformats.rst
deleted file mode 100644
index d4ffe5f2..00000000
--- a/core/wireformats.rst
+++ /dev/null
@@ -1,62 +0,0 @@
-.. _wireformats:
-
-Wire Transfer Methods
-=====================
-
-A wire transfer is essential for the exchange to transfer funds into a merchant's
-account upon a successful deposit (see :ref:`deposit request <deposit>`). The
-merchant has to include the necessary information for the exchange to initiate the
-wire transfer.
-
-The information required for a wire transfer depends on the method of wire transfer
-used. Since the wire transfers differ for each region, we document here the
-ones currently supported by the exchange.
-
-X-TALER-BANK
-------------
-
-The ``x-taler-bank`` wire format is used for testing and for integration with Taler's
-simple "bank" system which in the future might be useful to set up a bank
-for a local / regional currency or accounting system. Using the ``x-taler-bank``
-wire method in combination with the Taler's bank, it is thus possible to
-fully test the Taler system without using "real" currencies. The URL
-format for ``x-taler-bank`` is simple, in that it only specifies an account
-number and the origin (domain and optionally a port) of the bank:
-
-.. code-block:: none
-
- payto://x-taler-bank/BANK_URI/ACCOUNT_IDENTIFIER
-
-The account identifier given must be a non-empty alphanumeric ASCII string. As with
-any ``payto://`` URI, additional fields may be present (after a ``?``), but
-are not required. The ``BANK_URI`` may include a port number. If none is
-given, ``https`` over port 443 is assumed. If a port number is
-given, ``http`` over the given port is to be used. Note that this
-means that you cannot run an ``x-taler-bank`` over ``https`` on a
-non-canonical port.
-
-Note that a particular exchange is usually only supporting one particular bank
-with the ``x-taler-bank`` wire format, so it is not possible for a merchant with
-an account at a different bank to use ``x-taler-bank`` to transfer funds across
-banks. After all, this is for testing and not for real banking.
-
-SEPA
-----
-
-The Single Euro Payments Area (SEPA) [#sepa]_ is a regulation for electronic
-payments. Since its adoption in 2012, all of the banks in the Eurozone and some
-banks in other countries adhere to this standard for sending and receiving
-payments. Note that the currency of the transfer will (currently) always be ``EUR``. In
-case the receiving account is in a currency other than ``EUR``, the receiving bank
-may convert the amount into that currency; currency exchange charges may be
-levied by the receiving bank.
-
-For the merchant to receive deposits through SEPA, the deposit request must
-follow the ``payto://`` specification for SEPA:
-
-.. code-block:: none
-
- payto://sepa/IBAN
-
-.. [#sepa] SEPA - Single Euro Payments Area:
- http://www.ecb.europa.eu/paym/sepa/html/index.en.html
diff --git a/design-documents/001-new-browser-integration.rst b/design-documents/001-new-browser-integration.rst
index 8dbe2a43..fde6d3b2 100644
--- a/design-documents/001-new-browser-integration.rst
+++ b/design-documents/001-new-browser-integration.rst
@@ -1,5 +1,5 @@
-Design Doc 001: New Browser Integration
-#######################################
+XX 01: New Browser Integration
+##############################
.. warning::
diff --git a/design-documents/002-wallet-exchange-management.rst b/design-documents/002-wallet-exchange-management.rst
index 9d10045a..1ce37205 100644
--- a/design-documents/002-wallet-exchange-management.rst
+++ b/design-documents/002-wallet-exchange-management.rst
@@ -1,10 +1,11 @@
-Design Doc 002: Wallet Exchange Management
-##########################################
+XX 02: Wallet Exchange Management
+#################################
.. note::
- This design document is currently a draft, it
- does not reflect any implementation decisions yet.
+ This design document is deprecated in favor of DD48.
+
+ Trusted exchanges and auditors are no longer something we have.
Summary
=======
@@ -40,7 +41,7 @@ audited by a trusted auditor.
An exchange might only be known the wallet temporarily. For example,
the wallet UI may allow the user to review the fee structure of an
exchange before the wallet is permanently added to the wallet.
-Once a an exchange is either (a) marked as trusted or (b) used for a
+Once an exchange is either (a) marked as trusted or (b) used for a
withdrawal operation, it is marked as permanent.
Exchanges that are not permanent will be automatically be removed
diff --git a/design-documents/003-tos-rendering.rst b/design-documents/003-tos-rendering.rst
index 3011775c..18f9027b 100644
--- a/design-documents/003-tos-rendering.rst
+++ b/design-documents/003-tos-rendering.rst
@@ -1,5 +1,5 @@
-Design Doc 003: ToS rendering
-#############################
+DD 03: ToS rendering
+####################
Summary
=======
@@ -22,6 +22,24 @@ way.
Proposed Solution
=================
+Internationalization
+--------------------
+
+The server will parse the ``Accept-Languages`` request header to determine
+which language the user will most likely want to read the terms of service
+in. If multiple languages are given, the server will check against the
+available languages and return the one with the highest preference.
+
+Additionally, the server will return an ``Avail-Languages`` header which
+details what other langauges the terms of service are available in. The
+user interface in the wallet should then allow the user to switch to one
+of these alternatives using some language switcher.
+
+
+Encoding
+--------
+
+
The service providers can output legal agreements in various formats,
determined via the ``"Accept: "`` request header. The format provider **must**
support the ``text/plain`` mime type. The format provider **must** support
diff --git a/design-documents/004-wallet-withdrawal-flow.rst b/design-documents/004-wallet-withdrawal-flow.rst
index 28e9c16b..49e11aaf 100644
--- a/design-documents/004-wallet-withdrawal-flow.rst
+++ b/design-documents/004-wallet-withdrawal-flow.rst
@@ -1,5 +1,5 @@
-Design Doc 004: Wallet Withdrawal Flow
-######################################
+DD 04: Wallet Withdrawal Flow
+#############################
Summary
=======
@@ -104,7 +104,7 @@ For those, the wallet should not offer the option to change an exchange.
After confirming the withdrawal,
the user is brought to the list of transactions of the current currency.
-It will include a pending `TransactionWithdrawal` which might require additional user confirmation
+It will include a pending ``TransactionWithdrawal`` which might require additional user confirmation
such as a two-factor-authentication step with the bank.
1. The bank transfer happens immediately
@@ -114,7 +114,7 @@ such as a two-factor-authentication step with the bank.
3. The bank provides a ``bankConfirmationUrl`` that the user needs to visit.
If the withdrawal proceeds very quickly,
-the `TransactionWithdrawal` might not show as pending
+the ``TransactionWithdrawal`` might not show as pending
and its effective amount is added to the displayed balance right away.
Alternatives
diff --git a/design-documents/005-wallet-backup-sync.rst b/design-documents/005-wallet-backup-sync.rst
index 20fce37b..1e74914c 100644
--- a/design-documents/005-wallet-backup-sync.rst
+++ b/design-documents/005-wallet-backup-sync.rst
@@ -1,5 +1,5 @@
-Design Doc 005: Wallet Backup and Sync
-######################################
+XX 05: Wallet Backup and Sync
+#############################
.. warning::
@@ -44,7 +44,7 @@ The managed entities are:
* set of reserves together with reserve history
* set of accepted bank withdrawal operations
* set of coins together with coin history and blinding secret (both for normal withdrawal and refresh)
- and coin source info (refresh operation, tip, reserve)
+ and coin source info (refresh operation, reward, reserve)
* set of purchases (contract terms, applied refunds, ...)
* assignment of coins to their "primary wallet"
@@ -56,13 +56,13 @@ Entities that are **not** synchronized are:
* withdrawal operations before they have been accepted by the user
Entities that **could** be synchronized (to be decided):
-
+
* private keys of other sync accounts
* coin planchets
-* tips before the corresponding coins have been withdrawn
+* rewards before the corresponding coins have been withdrawn
* refresh sessions (not only the "meta data" about the operation,
but everything)
-
+
Garbage collection
------------------
diff --git a/design-documents/006-extensions.rst b/design-documents/006-extensions.rst
new file mode 100644
index 00000000..25afe3bc
--- /dev/null
+++ b/design-documents/006-extensions.rst
@@ -0,0 +1,223 @@
+DD 06: Extensions for GNU Taler
+###############################
+
+Summary
+=======
+
+This design document describes a generic framework for how extensions (i.e.
+optional features) to GNU Taler can be offered and used by the exchange,
+merchants and wallets.
+
+Motivation
+==========
+
+GNU Taler's list of supported features evolves over time. For example, the
+following features are going to be designed and implemented during the course
+of 2021 and 2022:
+
+* Peer-to-peer payments
+* Anonymous age-restriction
+* Escrow service for anonymous auctions
+* A general escrow service
+
+We call a feature an *extension* when it is *optional* for either the
+exchange, wallet or merchant to enable and support it. (However, enabling
+a feature might *require* the other parties to support the feature, too)
+
+For optional features we therefore need a mechanism to express the
+availability, version and configuration of a particular feature, f.e. p2p or
+age-restriction offered by an exchange, and make it verifiable by the other
+participants.
+
+Requirements
+============
+
+
+Proposed Solution
+=================
+
+Exchange
+^^^^^^^^
+
+The exchange will add two new *optional* fields in response to ``/keys``:
+
+#. The field ``extensions`` which contains a dictionary of
+ extension-names and their configuration, see below.
+
+#. The field ``extensions_sig`` that contains the EdDSA signature of the
+ SHA256-hash of the normalized JSON-string of the ``extensions`` object.
+
+
+The necessary changes to ``ExtensionsManifestsResponse`` are highlighted here:
+
+.. ts:def:: ExtensionsManifestsResponse
+
+ interface ExtensionsManifestsResponse {
+ //...
+
+ // Optional field with a dictionary of (name, object) pairs defining the
+ // supported and enabled extensions.
+ // The name MUST be non-empty and unique.
+ extensions?: { name: ExtensionManifest };
+
+ // Signature by the exchange master key of the SHA-256 hash of the
+ // normalized JSON-object of field ``extensions``, if it was set.
+ // The signature MUST have purpose ``TALER_SIGNATURE_MASTER_EXTENSIONS``.
+ extensions_sig?: EddsaSignature;
+
+ //...
+ }
+
+
+Extension names
+---------------
+
+The names of extensions MUST be unique. The full name MUST be registered with
+GANA_ along with a full description of the extension.
+
+.. _GANA: https://git.gnunet.org/gana.git
+
+(In the rare situation that the exchange might have to provide *multiple*
+versions of the "same" feature in parallel, multiple unique names MUST be used,
+f.e. ``age_restriction`` an ``age_restriction.v2``.)
+
+ExtensionManifest object
+---------------------------
+
+The definition of ``ExtensionManifest`` object itself is mostly up to the
+particular feature. **However**, it MUST have
+
+#. the boolean field ``critical`` that has the same semantics as as "critical"
+ has for extensions in X.509_: if true, the client must "understand" the
+ extension before proceeding, if "false" clients can safely skip extensions
+ they do not understand.
+
+#. the field ``version`` of type `LibtoolVersion` which contains the version
+ information of the extension in Taler's `protocol version ranges notation`_.
+
+.. _X.509: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2
+
+.. _`protocol version ranges notation`: https://docs.taler.net/core/api-common.html#protocol-version-ranges
+
+.. ts:def:: ExtensionManifest
+
+ interface ExtensionManifest {
+ // The criticality of the extension MUST be provided. It has the same
+ // semantics as "critical" has for extensions in X.509:
+ // - if "true", the client must "understand" the extension before
+ // proceeding,
+ // - if "false", clients can safely skip extensions they do not
+ // understand.
+ // (see https://datatracker.ietf.org/doc/html/rfc5280#section-4.2)
+ critical: boolean;
+
+ // The version information MUST be provided in Taler's protocol version
+ // ranges notation, see
+ // https://docs.taler.net/core/api-common.html#protocol-version-ranges
+ version: LibtoolVersion;
+
+ // Optional configuration object, defined by the feature itself
+ config?: object;
+ }
+
+
+Configuration
+-------------
+
+Extensions are *disabled* per default and must *explicetly* be enabled in the
+the TALER configuration manually. The configurations of all enabled extensions
+are signed with the master key and uploaded to the exchange with the tool
+``taler-exchange-offline``.
+
+Each extension has its own section in the configuration, starting with the
+prefix ``exchange-extension-``, like ``[exchange-extension-age_restriction]``.
+The field ``ENABLED = YES|NO`` is used to enable or disable the corresponding
+extension. If the extension has its own configuration parameters, they MAY be
+optional, in which case the ``taler-exchange-offline`` tool MUST fill them with
+safe default values.
+
+The ``taler-exchange-offline`` tool MUST offer the subcommand ``extensions``
+for showing and signing extensions. For this purpose, the following
+sub-subcommands MUST be available:
+
+* ``extensions show``: List all available extensions, their versions,
+ criticality and whether they are enabled.
+* ``extensions sign``: Sign the configuration of all enabled extensions with
+ the master key and prepare a JSON-object for the ``upload`` command.
+
+When extensions are offered and enabled by an exchange, the ``extensions``
+object MUST be signed by the exchange's master signing key. Whenever
+extensions are enabled or disabled, the offline tool MUST sign the SHA256 hash
+of the normalized JSON-string of the ``extensions`` object, if it is not empty.
+
+In order to do so, the ``taler-exchange-offline`` tool MUST
+
+#. have the complete list of all available optional features/extensions and
+ their versions builtin and
+
+#. understand them (including the version). For example, the extension for
+ age-restriction will require the exchange to perform particular steps when
+ this extension is enabled (i.e. signing denominations with support with age
+ restriction *together* with the string of age groups).
+
+#. reject a configuration that refers to any extension that the tool does not
+ know or understand.
+
+Similarly, the exchange MUST reject a signed configuration with extensions it
+does not know or understand.
+
+Examples
+--------
+
+A configuration for age-restriction in the taler configuration would look like
+this:
+
+.. code:: none
+
+ [exchange-extension-age_restriction]
+ ENABLED = true
+ # default:
+ AGE_GROUPS = "8:10:12:14:16:18:21"
+
+
+ [exchange-extension-policy_brandt_vickery_auction]
+ ENABLED = true
+ REPLAY_PROGRAM = "/usr/local/bin/taler-exchange-auction_replay"
+
+
+Merchant
+^^^^^^^^
+
+TODO:
+
+* Needs to express support for particular extensions, too. F.e. age-restriction.
+
+Extension Plugins
+==================
+
+TODO:
+
+* describe ``struct TALER_Extension``
+* describe the plugin loading mechanism for extensions
+* describe the various handlers
+
+
+Alternatives
+============
+
+TODO. None yet.
+
+
+Drawbacks
+=========
+
+* We do not offer (yet) any lifetime cycle of a feature, that is: There are
+ only two states that a feature can be in: "available" or "not-available".
+
+* The existing design for peer-to-peer payments must be adapted to this.
+
+Discussion / Q&A
+================
+
+The initial ideas presented here are based on discussions between Özgür Kesim
+and Christian Grothoff.
diff --git a/design-documents/007-payment.rst b/design-documents/007-payment.rst
index 115ac3f8..f9b0639a 100644
--- a/design-documents/007-payment.rst
+++ b/design-documents/007-payment.rst
@@ -1,5 +1,5 @@
-Design Doc 007: Specification of the Payment Flow
-#################################################
+DD 07: Specification of the Payment Flow
+########################################
Summary
=======
diff --git a/design-documents/008-fees.rst b/design-documents/008-fees.rst
index 47c2af8a..cb0ae7dc 100644
--- a/design-documents/008-fees.rst
+++ b/design-documents/008-fees.rst
@@ -1,10 +1,10 @@
-Design Doc 008: Fee Structure Metrics
-#####################################
+XX 08: Fee Structure Metrics
+############################
.. note::
- This design document is currently a draft, it
- does not reflect any implementation decisions yet.
+ This design document is deprecated.
+
Summary
=======
diff --git a/design-documents/009-backup.rst b/design-documents/009-backup.rst
index 04ae628c..18571198 100644
--- a/design-documents/009-backup.rst
+++ b/design-documents/009-backup.rst
@@ -1,5 +1,5 @@
-Design Doc 009: Wallet Backup
-#############################
+DD 09: Wallet Backup
+####################
Summary
=======
diff --git a/design-documents/010-exchange-helpers.rst b/design-documents/010-exchange-helpers.rst
index e67fca4e..c63921b6 100644
--- a/design-documents/010-exchange-helpers.rst
+++ b/design-documents/010-exchange-helpers.rst
@@ -1,5 +1,5 @@
-Design Doc 010: Exchange crypto helper design
-#############################################
+DD 10: Exchange crypto helper design
+####################################
Summary
=======
@@ -13,7 +13,7 @@ Motivation
We want to provide an additional layer of protection for the private online
signing keys used by the exchange. The exchange is network-facing, includes an
-HTTP server, Postgres interaction, JSON parser and quite a bit of other logic
+HTTP server, PostgreSQL interaction, JSON parser and quite a bit of other logic
which may all be theoretically vulnerable to remote exploitation. Thus, it
would be good from a security perspective to protect the private online
signing keys via an additional layer of protection.
@@ -89,7 +89,7 @@ Exchange design considerations:
exchange. This simplifies the exchange, and we already needed the
exchange operator to start four processes to operate an exchange.
So this number simply increases to six (not even counting the
- Postgres database and a reverse HTTP proxy for TLS termination).
+ PostgreSQL database and a reverse HTTP proxy for TLS termination).
* Each exchange thread will create its own connection to the helpers, and will
block while waiting on the helper to create a signature. This keeps the
exchange logic simple and similar to the existing in-line signing calls.
@@ -108,7 +108,7 @@ New exchange endpoints:
sign based on that file, and then upload the resulting signature back to
the exchange. For this, master signatures will be POSTed to
the exchange to the ``/keys`` endpoint.
- The exchange will keep those signatures in the Postgres database.
+ The exchange will keep those signatures in the PostgreSQL database.
* A new endpoint (``/auditors``) will also allow adding/removing auditors
(POST, DELETE) using requests signed with the offline master private key.
Once an auditor has been added, the respective auditor signatures on exchange
diff --git a/design-documents/011-auditor-db-sync.rst b/design-documents/011-auditor-db-sync.rst
index fb2e3bea..71d0762a 100644
--- a/design-documents/011-auditor-db-sync.rst
+++ b/design-documents/011-auditor-db-sync.rst
@@ -1,5 +1,5 @@
-Design Doc 011: Auditor-Exchange Database Synchronization
-#########################################################
+DD 11: Auditor-Exchange Database Synchronization
+################################################
Summary
=======
@@ -62,7 +62,7 @@ Proposed Solution
=================
* Use "common" incremental database replication (whichever is
- approproate for the exchange database setup, synchronous
+ appropriate for the exchange database setup, synchronous
or asynchronous) to make a 1:1 copy of the exchange database
at the auditor. This should work for any full-featured
modern database. This "ingress" copy cannot be trusted, as constraint
@@ -89,9 +89,9 @@ Proposed Solution
* The auditor's "ingress" database should be well isolated from
the rest of the auditor's system and database
(different user accounts). The reason is that we should not
- assume that the Postgres replication code is battle-tested with
+ assume that the PostgreSQL replication code is battle-tested with
malicious parties in mind.
-* The canonical Postgres synchronization between exchange and the
+* The canonical PostgreSQL synchronization between exchange and the
auditor's "ingress" database must use transport security.
The above solution does not gracefully handle mutable tables on which
@@ -148,10 +148,10 @@ A good order for replicating the tables should be:
Alternatives
============
-* Copy the Postgres WAL, filter it for "illegal" operations
+* Copy the PostgreSQL WAL, filter it for "illegal" operations
and then apply it at the auditor end. Disadvantages: WAL
filtering is not a common operation (format documented?),
- this would be highly Postgres-specific, and would require
+ this would be highly PostgreSQL-specific, and would require
complex work to write the filter. Also unsure how one
could later recover gracefully from transient errors
(say where the exchange recified a bogus DELETE).
diff --git a/design-documents/012-fee-schedule-metrics.rst b/design-documents/012-fee-schedule-metrics.rst
index 8eb36da7..fb7b295a 100644
--- a/design-documents/012-fee-schedule-metrics.rst
+++ b/design-documents/012-fee-schedule-metrics.rst
@@ -1,5 +1,5 @@
-Design Doc 012: Exchange Fee Configuration
-##########################################
+DD 12: Exchange Fee Configuration
+#################################
.. note::
@@ -466,7 +466,7 @@ Note that for a typical transaction, the number of coins is logarithmic to the
amount. So with the above fee structure, paying amounts around 10 EUR would on
average involve about 6 coins with 1/3rd fees at 0.005, 1/3rd fees at 0.01 and
1/3rd fees at 0.015, resulting in an expected total transaction cost in
-**deposit** fees of 0.03 EUR. In constrast, paying 0.50 cents would require
+**deposit** fees of 0.03 EUR. In contrast, paying 0.50 cents would require
on average 4 coins cost less than 0.02 EUR in **deposit** fees. As a result
of this fee structure, microtransactions with Taler have a higher fee in terms
of percentage, while larger transactions are still highly competitive.
@@ -544,4 +544,4 @@ Other documents regarding fee specifications:
* Fee schedule and metrics from the users' point of view :doc:`008-fees`
-* Wire fee for different wiring methods (``sepa`` or ``x-taler-wire``) <https://docs.taler.net/taler-exchange-manual.html#wire-fee-structure>
+* Wire fee for different wiring methods (``iban`` or ``x-taler-wire``) <https://docs.taler.net/taler-exchange-manual.html#wire-fee-structure>
diff --git a/design-documents/013-peer-to-peer-payments.rst b/design-documents/013-peer-to-peer-payments.rst
index c44ab348..20124532 100644
--- a/design-documents/013-peer-to-peer-payments.rst
+++ b/design-documents/013-peer-to-peer-payments.rst
@@ -1,5 +1,5 @@
-Design Doc 013: Wallet-to-Wallet Payments
-#########################################
+DD 13: Wallet-to-Wallet Payments
+################################
Summary
=======
@@ -376,6 +376,8 @@ In this protocol variant, the payer is initiating the process.
3. The payer shares the purse's private key and the base URL
of the exchange where the purse was created with the payee.
This can be done using a ``taler://purse/$BASE_URL/$PURSE_PRIV`` URL.
+ The chapter on ``Refinements`` below clarifies why this
+ step is not quite OK and was modified when implementing the design.
4. The payee uses the new ``/purse/$PURSE_PUB`` endpoint to retrieve
the encrypted contract (if available) and purse balance, which includes all
(coin) deposits and **merges** involving the purse.
@@ -422,7 +424,7 @@ Payment requests
1. The payee creates a **purse** by computing a public-private key pair.
2. The payee POSTs to the ``/purse/$PURSE_PUB/merge`` endpoint to
- both upload the encrypted contract, associate it with the payer's
+ both upload the encrypted contract, associate it with the payee's
account and signal its agreement to the contract. The
**merge** request must be signed by the purse's private key.
A second signature must be provided by the account private key,
@@ -703,7 +705,6 @@ database.)
(merge_request_serial_id BIGSERIAL UNIQUE
,reserve_uuid BYTEA NOT NULL REFERENCES reserves (reserve_uuid) ON DELETE CASCADE
,partner_serial_id INT8 REFERENCES partners(partner_serial_id) ON DELETE CASCADE,
- ,reserve_url TEXT NOT NULL,
,reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32),
,purse_pub BYTEA NOT NULL CHECK (LENGTH(purse_pub)=32),
,reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64))
@@ -721,8 +722,6 @@ database.)
IS 'identifies the reserve';
COMMENT ON COLUMN mergers.partner_serial_id
IS 'identifies the partner exchange, NULL in case the target reserve lives at this exchange';
- COMMENT ON COLUMN mergers.reserve_url
- IS 'payto://-URL of the reserve, identifies the exchange and the reserve';
COMMENT ON COLUMN mergers.reserve_pub
IS 'public key of the target reserve';
COMMENT ON COLUMN mergers.purse_pub
@@ -821,7 +820,6 @@ database.)
CREATE TABLE IF NOT EXISTS purse_deposits
(purse_deposit_serial_id BIGSERIAL UNIQUE
,purse_pub BYTEA NOT NULL CHECK (LENGTH(purse_pub)=32),
- ,purse_expiration INT8 NOT NULL
,coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) ON DELETE CASCADE
,amount_with_fee_val INT8 NOT NULL
,amount_with_fee_frac INT4 NOT NULL
@@ -832,8 +830,6 @@ database.)
IS 'Requests depositing coins into a purse';
COMMENT ON COLUMN purse_deposits.purse_pub
IS 'Public key of the purse';
- COMMENT ON COLUMN purse_deposits.purse_expiration
- IS 'When the purse is set to expire';
COMMENT ON COLUMN purse_deposits.coin_pub
IS 'Public key of the coin being deposited';
COMMENT ON COLUMN purse_deposits.amount_with_fee_val
@@ -1072,6 +1068,33 @@ Aside from implementation complexity, the solution has the following drawbacks:
account private key before initiating the KYC process.
+Refinements
+===========
+
+In the original design, a payer making a payment offer sends the purse private
+key to the payee, so that the payee can sign the merge request with it. This
+creates a security issue, as theoretically the payee could sign a different
+contract with the purse private key, and conspire with the exchange to replace
+the original contract. In this case, the payer would be making a payment to
+the "wrong" contract, and have no proof of the exchange an payee conspiring
+against it.
+
+A simple fix seems possible: instead of having simply one public-private key
+pair for a purse, we have a PayerContractKey and a PurseMergeKey pair. The payer
+would pay into a purse identified by the PayerContractKey and associate a
+PurseMergeKey with the purse. The payer can then safely share the
+PayeeMergeKey with the payee, as it is ONLY useful for the merge and not to
+sign the contract. Payments would be made into a purse identified by the
+PurseContractKey.
+
+When payments flow in the other direction, the split of the keys seems
+unnecessary (as only a public key is transmitted anyway. However, schema-wise,
+signing the contract with the PurseContractKey and the merge with the
+PurseMergeKey would still work. Only the public PurseContractKey would need
+to be sent to the payer.
+
+
+
Q / A
=====
diff --git a/design-documents/014-merchant-backoffice-ui.rst b/design-documents/014-merchant-backoffice-ui.rst
index 8c4104dc..1f744a15 100644
--- a/design-documents/014-merchant-backoffice-ui.rst
+++ b/design-documents/014-merchant-backoffice-ui.rst
@@ -1,5 +1,5 @@
-Design Doc 014: Merchant backoffice UI
-######################################
+DD 14: Merchant backoffice UI
+#############################
Motivation
@@ -139,11 +139,3 @@ Story #4: Manage inventory
- change product description / price / etc.
- delete products from inventory
-
-
-Story #5: Manage tipping
-------------------------
-
-- set up tipping reserve
-
-- check tipping reserve status
diff --git a/design-documents/015-merchant-backoffice-routing.rst b/design-documents/015-merchant-backoffice-routing.rst
index f6372dcc..71a0e554 100644
--- a/design-documents/015-merchant-backoffice-routing.rst
+++ b/design-documents/015-merchant-backoffice-routing.rst
@@ -1,21 +1,21 @@
-Design Doc 015: Merchant backoffice Routing
-###########################################
+DD 15: Merchant backoffice Routing
+##################################
Motivation
==========
A well defined routing will allow users to share backoffice links pointing
-directly into instance pages (settings, orders, products, etc...)
+directly into instance pages (settings, orders, products, etc...)
-The backoffice should load from the instance URL and then allow a internal
+The backoffice should load from the instance URL and then allow an internal
routing of the views with the possibility to accessing them directly when
sharing a link.
This 3 definitions are going to be use in this document:
-* BACKOFFICE_URL as the url where the app is loaded.
-
+* BACKOFFICE_URL as the url where the app is loaded.
+
* BACKEND_URL as the url where the merchant backend is.
* INSTANCE the name of the instance being manage
@@ -27,13 +27,13 @@ Application Ready definition
The application is considered ready after
* the user tried to login.
-
+
* the application checked that the backend url points to a merchant backend
* the merchant backend response successfully
The backoffice test for ``$BACKEND_URL/config`` to define if the $BACKEND_URL is ok.
-The application can potentially test if the protocol or version matched.
+The application can potentially test if the protocol or version matched.
While the application is not ready, just the top navigation bar will be shown
with a message in the left and the lang selection option.
@@ -58,7 +58,7 @@ Knowing that the $BACKEND_URL points to a correct merchant backend the SPA will
check for ``$BACKEND_URL/management/instances``:
* if Unauthorized ask for credentials
-
+
* if error check with the user
* if not found, then url should end with ``/instances/$INSTANCE``. otherwise is
@@ -69,11 +69,11 @@ check for ``$BACKEND_URL/management/instances``:
When a user access the SPA there are 3 scenarios possible:
* **standard**: admin is false so BACKEND_URL points to a non-default instance.
- standard features and links are shown
+ standard features and links are shown
* **admin**: admin is true so BACKEND_URL point to default instance. same as
before and user can create and list instances with some additional links in
- the sidebar.
+ the sidebar.
* **mimic**: admin is true and the request parameter "instance" is set $INSTANCE
instance. BACKEND_URL point to default instance but the user is managing
@@ -99,7 +99,7 @@ parameter (like order id or product id) it should be accessible from the Sidebar
If the user has admin access, this entry points are available:
- /instances: Show the list of instances currently created
- - /instance/new: Show a instance creation form
+ - /instance/new: Show an instance creation form
Where admin or not, there is also this entry points:
@@ -145,7 +145,7 @@ credentials or the backend url
Not found
---------
-For any case that the backend respond 404 the application will render a
+For any case that the backend respond 404 the application will render a
custom not found page
Default instance is missing
@@ -155,6 +155,3 @@ If the **user is admin** AND is loading the setting page (/update), product list
(/products), order list (/orders) or transfer list (/transfers) AND **gets a
404** it will tell the user that it need to create a default instance before
proceeding.
-
-
-
diff --git a/design-documents/016-backoffice-order-management.rst b/design-documents/016-backoffice-order-management.rst
index 00250cd2..09af5eb5 100644
--- a/design-documents/016-backoffice-order-management.rst
+++ b/design-documents/016-backoffice-order-management.rst
@@ -1,5 +1,5 @@
-Design Doc 016: Backoffice Order Management
-###########################################
+DD 16: Backoffice Order Management
+##################################
Summary
=======
@@ -32,10 +32,10 @@ Proposed Solution
Listing orders
--------------
-.. image:: ../backoffice-order-list.svg
+.. image:: ../images/backoffice-order-list.svg
:width: 800
-4 tabs will be show for a easy access to common filter, click on any of this and
+4 tabs will be show for an easy access to common filter, click on any of this and
search will reset all filter except date
* paid (default)
@@ -88,7 +88,7 @@ This section has two parts:
The first part will add/remove product from the current stock.
* ``name``: search box to select product by description field. if not found it
- will be a 'create new' option leading to the create product without loosing
+ will be a 'create new' option leading to the create product without losing
context
* ``quantity``: mandatory
@@ -101,7 +101,7 @@ In both cases, the total unit and price of the products will be calculated and
shown in the bottom of the section. If the merchant collapse one of the product
list a line with a resume of the total price and units will be shown.
-.. image:: ../backoffice-order-create.product-section.svg
+.. image:: ../images/backoffice-order-create.product-section.svg
:width: 800
Create order: Price section
@@ -117,7 +117,7 @@ of all products prices will be shown. The ``order price`` will default to
``total products price``. The ``products taxes`` and ``profit`` will be shown
since ``order price`` cannot be less that ``product taxes``.
-.. image:: ../backoffice-order-create.price-section.svg
+.. image:: ../images/backoffice-order-create.price-section.svg
:width: 800
Create order: Payment section
@@ -142,7 +142,7 @@ This section show optional values that can be overwritten by the merchant
* ``wire_fee_amortization``: default value from the instance
-.. image:: ../backoffice-order-create.payment-section.svg
+.. image:: ../images/backoffice-order-create.payment-section.svg
:width: 800
Create order: all section expanded
@@ -150,7 +150,7 @@ Create order: all section expanded
An example of how all section in a page will be shown.
-.. image:: ../backoffice-order-create.all-expanded.svg
+.. image:: ../images/backoffice-order-create.all-expanded.svg
:width: 800
@@ -291,10 +291,10 @@ Ask for:
* drop down options: duplicated, requested by customer, other
* after selecting, free text for additional information
-.. image:: ../backoffice-order-refund.svg
+.. image:: ../images/backoffice-order-refund.svg
:width: 800
-.. image:: ../backoffice-order-refund.already.svg
+.. image:: ../images/backoffice-order-refund.already.svg
:width: 800
Example of details by status
@@ -302,16 +302,16 @@ Example of details by status
-.. image:: ../backoffice-order-details.paid.svg
+.. image:: ../images/backoffice-order-details.paid.svg
:width: 800
-.. image:: ../backoffice-order-details.unpaid.svg
+.. image:: ../images/backoffice-order-details.unpaid.svg
:width: 800
-.. image:: ../backoffice-order-details.claimed.svg
+.. image:: ../images/backoffice-order-details.claimed.svg
:width: 800
-.. image:: ../backoffice-order-details.refunded.svg
+.. image:: ../images/backoffice-order-details.refunded.svg
:width: 800
@@ -323,7 +323,7 @@ pagination
----------
order list was originally thought with pagination footer
-.. image:: ../backoffice-order-list.pagination.svg
+.. image:: ../images/backoffice-order-list.pagination.svg
:width: 800
ascending boolean flag cloud be eliminated using the load before and load after
diff --git a/design-documents/017-backoffice-inventory-management.rst b/design-documents/017-backoffice-inventory-management.rst
index b2fc6dfd..9565d53e 100644
--- a/design-documents/017-backoffice-inventory-management.rst
+++ b/design-documents/017-backoffice-inventory-management.rst
@@ -1,5 +1,5 @@
-Design Doc 017: Backoffice Inventory Management
-###############################################
+DD 17: Backoffice Inventory Management
+######################################
Summary
=======
@@ -31,7 +31,7 @@ Proposed Solution
Inspecting inventory
--------------------
-.. image:: ../backoffice-product-list.svg
+.. image:: ../images/backoffice-product-list.svg
:width: 800
Listing the product will shown this columns:
@@ -53,9 +53,9 @@ Actions will be
Create and Update Product form
------------------------------
-.. image:: ../backoffice-product-create.svg
+.. image:: ../images/backoffice-product-create.svg
:width: 800
-
+
Update product will use the same form except for the ``product_id``
* product_id: BACKOFFICE_URL + id
@@ -64,7 +64,7 @@ Update product will use the same form except for the ``product_id``
* name: required, one line
* extra: optional, free text area
-* description localized: list with
+* description localized: list with
* lang: dropdown list with supported lang + custom
* description: text area
@@ -95,7 +95,7 @@ Stock management
* ``never`` button will set next restock to never
-* when updating the product, the option ``without stock`` will no be available
+* when updating the product, the option ``without stock`` will no be available
if the product already has stock
* if the product already exist then:
@@ -111,7 +111,7 @@ Stock management
* a label at the end of the section will inform about the final result
-.. image:: ../backoffice-product-create.stock.svg
+.. image:: ../images/backoffice-product-create.stock.svg
:width: 800
@@ -119,16 +119,16 @@ Alternatives
============
* price and stock columns in the list can be merged into a more complex column
- with the same information
+ with the same information
* rows in the table can be expandable when clicked to get access to some common
actions like increase stock or change price
-.. image:: ../backoffice-product-list.actions.svg
+.. image:: ../images/backoffice-product-list.actions.svg
:width: 800
* detail page was intentionally left out since all information can be access
- from the update page
+ from the update page
Q&A
===
@@ -138,8 +138,4 @@ Q&A
* can we allow add extra data like order has in contractTerm?, this could be
useful for frontend apps. example of usage: country/state to where the product
- is sold since taxes may vary
-
-
-
-
+ is sold since taxes may vary
diff --git a/design-documents/018-contract-json.rst b/design-documents/018-contract-json.rst
index d7f78257..051ed2f1 100644
--- a/design-documents/018-contract-json.rst
+++ b/design-documents/018-contract-json.rst
@@ -1,5 +1,5 @@
-Design Doc 018: Forgettable Data in JSON Contract Terms
-#######################################################
+DD 18: Forgettable Data in JSON Contract Terms
+##############################################
Summary
=======
@@ -92,7 +92,7 @@ scrubbed and canonicalized value is put into the special ``$forgotten$``
member of the parent object.
-.. code-block:: json
+.. code-block:: javascript
{
...props,
@@ -149,7 +149,7 @@ SHA512.
Test vector
-----------
-The follwing input contains top-level and nested forgettable
+The following input contains top-level and nested forgettable
fields, as well as booleans, integers, strings and objects
as well as non-forgettable fields. It is thus suitable as
a minimal interoperability test:
diff --git a/design-documents/019-wallet-backup-merge.rst b/design-documents/019-wallet-backup-merge.rst
index caf45401..9823f69d 100644
--- a/design-documents/019-wallet-backup-merge.rst
+++ b/design-documents/019-wallet-backup-merge.rst
@@ -1,5 +1,5 @@
-Design Doc 019: Wallet Backup Merging
-#####################################
+DD 19: Wallet Backup Merging
+############################
Summary
=======
diff --git a/design-documents/020-backoffice-tips-management.rst b/design-documents/020-backoffice-rewards-management.rst
index 566f8fb5..8345a3b9 100644
--- a/design-documents/020-backoffice-tips-management.rst
+++ b/design-documents/020-backoffice-rewards-management.rst
@@ -1,10 +1,10 @@
-Design Doc 020: Backoffice Tips Management
-##########################################
+XX 20: Backoffice Rewards Management
+####################################
Summary
=======
-This document describe the complete list features for tips and reserve
+This document describe the complete list features for rewards and reserve
management and how will be shown.
Motivation
@@ -19,9 +19,9 @@ User should use the backoffice to:
* creating new reserves
* listing active reserves
-* authorize tips for a reserve
-* list all tips for an active reserve
-* check tips status
+* authorize rewards for a reserve
+* list all rewards for an active reserve
+* check rewards status
Proposed Solution
=================
@@ -29,7 +29,7 @@ Proposed Solution
Listing reserves
----------------
-.. image:: ../backoffice-reserve-list.svg
+.. image:: ../images/backoffice-reserve-list.svg
:width: 400
@@ -47,14 +47,14 @@ columns:
* initial: if the exchange and merchant-backend disagree in the initial balance
(failure) the cell will be red and have a tooltip with more information
-* actions: delete button will be disabled on failure or committed > 0, new_tip
+* actions: delete button will be disabled on failure or committed > 0, new_reward
button will be disabled on picked_up == initial or failure
Create new reserve
------------------
-.. image:: ../backoffice-reserve-create.svg
+.. image:: ../images/backoffice-reserve-create.svg
:width: 400
fields:
@@ -67,31 +67,29 @@ fields:
If there is an error in the creation a Notification message will be shown
-Authorize Tip
--------------
+Authorize Reward
+----------------
-The merchant can authorize tips clicking in the plus (+) button that will bring
+The merchant can authorize rewards clicking in the plus (+) button that will bring
the next popup
-.. image:: ../backoffice-tip-create.svg
+.. image:: ../images/backoffice-reward-create.svg
:width: 400
after confirm it will continue with a success page:
-.. image:: ../backoffice-tip-create.confirmation.svg
+.. image:: ../images/backoffice-reward-create.confirmation.svg
:width: 400
Details of reserve
-----------------------------
+------------------
-.. image:: ../backoffice-reserve-details.svg
+.. image:: ../images/backoffice-reserve-details.svg
:width: 400
-Tips sorted from newer to older
+Rewards sorted from newer to older
When the reserve has not yet funded
-.. image:: ../backoffice-reserve-details.unfunded.svg
+.. image:: ../images/backoffice-reserve-details.unfunded.svg
:width: 400
-
-
diff --git a/design-documents/021-exchange-key-continuity.rst b/design-documents/021-exchange-key-continuity.rst
index e09b6fe0..769cff72 100644
--- a/design-documents/021-exchange-key-continuity.rst
+++ b/design-documents/021-exchange-key-continuity.rst
@@ -1,5 +1,5 @@
-Design Doc 021: Exchange Key Continuity
-#######################################
+DD 21: Exchange Key Continuity
+##############################
Summary
=======
diff --git a/design-documents/022-wallet-auditor-reports.rst b/design-documents/022-wallet-auditor-reports.rst
new file mode 100644
index 00000000..1cbb2a21
--- /dev/null
+++ b/design-documents/022-wallet-auditor-reports.rst
@@ -0,0 +1,54 @@
+DD 22: Wallet Proofs to Auditor
+###############################
+
+.. note::
+
+ Status (2021-05-25): Writing in progress.
+
+
+Summary
+=======
+
+This design document defines the structure and contents of proofs
+of misbehavior that the wallet sends to auditors.
+
+Motivation
+==========
+
+There are some situations where the wallet learns that some entity did
+something against the protocol specification. When the wallet has
+cryptographic proof for this, this proof should be stored in the database and
+eventually be exportable to auditors, courts, etc.
+
+Requirements
+============
+
+* Users should be able to review all the information that
+ a misbehavior proof would reveal.
+
+Proposed Solution
+=================
+
+Types of Misbehavior
+--------------------
+
+This section collects all types of misbehavior for which the wallet
+can export cryptographic proof.
+
+* ``exchange-denomination-spec-inconsistent``
+
+ An exchange has announced a denomination with the same
+ denomination public key, but different metadata (value, expiration)
+
+* ``exchange-denomination-gone``
+
+ The exchange is not accepting/listing a denomination
+ anymore that it previously listed.
+
+
+Discussion / Q&A
+================
+
+* What about complaints to the auditor that do not contain
+ cryptographic proof? (e.g. "exchange XYZ has not been responding
+ for the last 14 days")
diff --git a/design-documents/023-taler-kyc.rst b/design-documents/023-taler-kyc.rst
new file mode 100644
index 00000000..77dbe2bb
--- /dev/null
+++ b/design-documents/023-taler-kyc.rst
@@ -0,0 +1,1883 @@
+DD 23: Taler KYC
+################
+
+Summary
+=======
+
+This document discusses the Know-your-customer (KYC) and Anti-Money Laundering
+(AML) processes supported by Taler.
+
+
+Motivation
+==========
+
+To legally operate, Taler has to comply with KYC/AML regulation that requires
+banks to identify parties involved in transactions at certain points.
+
+
+Requirements
+============
+
+Taler needs to take *measures* based on the following primary *triggers*:
+
+* Customer withdraws money over a monthly threshold
+
+ * exchange triggers KYC
+ * key: IBAN (encoded as payto:// URI)
+
+* Wallet receives (via refunds) money resulting in a balance over a threshold
+
+ * this is a client-side restriction
+ * key: reserve (=KYC account) long term public key per wallet (encoded as payto:// URI)
+
+* Wallet receives money via P2P payments
+
+ * there are two sub-cases: PUSH and PULL payments
+ * key: reserve (=KYC account) long term public key per wallet (encoded as payto:// URI)
+
+* Merchant receives money (Q: any money, or above a monthly threshold?)
+
+ * key: IBAN (encoded as payto:// URI)
+
+* Reserve is "opened" for invoicing.
+
+ * key: reserve (=KYC account) long term public key per wallet (encoded as payto:// URI)
+
+* Import of new sanctions lists and triggering of measures against matches of existing
+ customer records against the list
+
+For the different operation types, there can be both soft
+and hard limits. Soft limits are those that the customer
+may raise by providing data and passing KYC checks.
+Hard limits cannot be lifted, for example because an
+exchange forbids crossing those limits in its terms of
+service for all customers.
+
+
+Process requirements
+^^^^^^^^^^^^^^^^^^^^
+
+The key consideration here is *plausibilization*: staff needs to
+check that the client-provided information is plausible. As this
+is highly case-dependent, this cannot be automated.
+
+For the different *measures*, there are various different possible KYC/AML
+*checks* that could happen:
+
+* In-person validation by AML staff
+* Various forms to be filled by AML staff
+* Validation involving local authorities and post-office
+* Online validation, sometimes with multiple options (like KYC for multiple people):
+
+ * Forms to be supplied by user (different types of ID)
+ * Interactive video
+ * Documents to be supplied (business register)
+ * Address validation (e-mail or phone or postal)
+
+Additionally, the process is dynamic and conditional upon various decisions:
+
+* Individual vs. business
+* PEP or non-PEP
+* Hit on sanctions list
+* Type of business (trust, foundation, listed on stock market, etc.)
+* Need for plausibilization (via documents by user or staff research)
+* Periodic updates (of customer data, of sanction lists) and re-assessment
+
+There are also various *outcomes*:
+
+* normal operation (with expiration date)
+* normal operation but with AML staff investigating (new measure)
+* held, requesting customer documentation (new measure)
+* held, AML staff reviewing evidence for plausibilization (new measure)
+* automatically frozen until certain day (due to sanctions)
+* institutionally frozen until certain day (due to order by state authority)
+* operation is categorically not allowed (at least above certain limits)
+
+Outcomes may also be (partially) public, that is exposed to the client. For
+example, we may want to tell a wallet that it has hit a hard withdraw limit,
+but might succeed at withdrawing a smaller amount.
+
+The outcome of a *check* can set new rules or trigger another *measure* (the
+latter is conditional on reaching the expiration time of the outcome).
+
+As a result, we largely end up in a large state machine where the AML staff has
+serious flexibiltiy while the user needs guidance as to the possible next moves
+and/or to the current state of their account (where some information must not be
+disclosed).
+
+
+Documentation requirements
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For each account we must:
+
+* define risk-profile (902.4, 905.1)
+* document the specific setup, likely not just the INI file
+* should have some key AMLA file attributes, such as:
+
+ * File opened, file closed (keep data for X years afterwards!)
+ * low-risk or high-risk business relationship
+ * PEP status
+ * business domain
+ * authority notification dates (possibly multiple) with
+ voluntary or mandatory notification classification
+
+Finally, we need to produce statistics:
+
+* There must be a page with an overview of AMLA files with opening
+ and closing dates and an easy way to determine for any day the
+ number of open AMLA files
+* Technically, we also need a list of at-risk transactions and of
+ frozen transactions, but given that we can really only freeze
+ on an account-basis, I think there is nothing to do here
+* number of incidents reported (voluntarily, required)
+* number of business relationships at any point in time
+* number of risky business relationships (PEP, etc.)
+* number of frozen transactions (authority vs. sanction) with start-date and end-date
+* start-data and end-date of relationships (data retained for X years after end of relationship)
+
+For this high-level monitoring, we need certain designated critical events to
+be tracked in the system statistics:
+
+* account opened
+* set to high risk
+* set to low risk
+* suspicious activity report filed with authority
+* account frozen
+* account unfrozen
+* account closed
+
+
+Further considerations
+^^^^^^^^^^^^^^^^^^^^^^
+
+On top of all of this, we need to plan some *diagnostics* to determine when
+components fail (such as scripts or external services providing malformed
+results).
+
+Optionally, in the future, the solution should support fees to be paid by the
+user for *voluntary* KYC processes related to attestation (#7365).
+
+
+Proposed Solution
+=================
+
+We allow certain *conditions* to *trigger* a single specific *measures*.
+For the different *measures*, we define:
+
+* Who has to do something (AML staff, user, nobody)
+* Contextual input data to be provided (with templating, e.g. amount set dynamically based on the *trigger*)
+* A *check* to be performed (user-interactive or staff-interactive)
+* Another *measure* to take on failure of a user-interactive check
+* A *program* that uses data from the *check* as well as *context* data
+ to determine an *outcome* which is the specific operational state
+ (normal, held on staff, held on user, frozen, etc.) the account is to transition to
+* What information about the state to show to the user (normal, information required, pending, etc.)
+
+For the user-interactive checks we need a SPA (for KYC) that is given:
+
+* instructions to render (with either a form to fill or links to external checks);
+ here the context could provide an array of choices!
+* possibly an external check that was set up (if any); for cost-reasons, we should only do one at a time,
+ and probably should then always redirect the browser to that check.
+
+For the staff-interactive checks we need a SPA (for AML):
+
+* to file forms and upload documentation (without state transition)
+* to decide on next measure (providing context); here, the exchange needs
+ to expose the list of available *measures* and required *context* for each
+
+For non-interactive measures (normal operation, account frozen) we need:
+
+* Expiration time (in context)
+* Measure to trigger upon expiration, again with context
+ (renew documents, resume normal operation, etc.)
+
+We need some customer-driven interactivity in KYB/KYC process, for example the
+user may need to be given choices (address vs. phone, individual vs. business,
+order in which to provide KYC data of beneficiaries). As a result, the
+exchange needs to serve some SPA for measures where the user is shown the next
+step(s) or choices (which person to collect KYC data on, whether to run
+challenger on phone number of physical address, etc.). The SPA should also
+potentially contain a form to allow the customer to directly upload documents
+to us (like business registration) instead of to some KYC provider. This is
+because KYC providers may not be flexible enough.
+
+Similarly, the AML staff will need to be able to trigger rather complex
+KYB/KYC processes, like "need KYC on X and Y and Z" or "phone number or
+mailing address" or "please upload form A/T/S". Here in particular it
+should be possible to request not only filled forms, but arbitrary
+documents.
+
+
+Terminology
+^^^^^^^^^^^
+
+* **Check**: A check establishes a particular attribute of a user, such as their name based on an ID document and lifeness, mailing address, phone number, taxpayer identity, etc. Checks may be given *context* (such as whether a customer is an individual or a business) to run correctly. Checks can also be AML staff inserting information for plausibilization. Checks result in an *outcome* being decided by an external AML *program*.
+
+* **Condition**: A condition specifies when KYC is required. Conditions include the *type of operation*, a threshold amount (e.g. above EUR:1000) and possibly a time period (e.g. over the last month).
+
+* **Configuration**: The configuration determines the *legitimization rules*, and specifies which providers offer which *checks* at what *cost*.
+
+* **Context**: Context is information provided as input into a *check* and *program* to customize their execution. The context is initially set by the *trigger*, but may evolve as the *account* undergoes *measures*. For each *check* and *program*, the required *context* data must be specified.
+
+* **Cost**: How much would a client have to pay for a KYC process (if they voluntarily choose to do so for attestation).
+
+* **Expiration**: KYC legitimizations may be outdated. Expiration rules determine when *checks* have to be performed again.
+
+* **Legitimization rules**: The legitimization rules determine under which *conditions* which *checks* must be performend and the *expiration* time period for the *checks*.
+
+* **Logic**: Logic refers to a specific bit of code (realized as an exchange plugin) that enables the interaction with a specific *provider*. Logic typically requires *configuration* for access control (such as an authorization token) and possibly the endpoint of the specific *provider* implementing the respective API.
+
+* **Measure**: Describes the possible outgoing edges from one state in the state machine (including how to show the current state). Each edge is given some *context* and a *check* to be performed as well as a *program* to decide the *outcome* and the next *measure*.
+
+* **Outcome**: Describes the account state that an account ends up in due to the result of a *check*. Outcomes can be that an account is frozen (no transactions possible until freeze expires), held (no transactions possible until another *measure* has been taken), or operating normally. Outcomes also include a new set of *legitimization rules* to apply and an expiration time at which point a new *measure* will be automatically taken. Finally, parts of the outcome may be explained to the client (for example, to allow a wallet to stay below hard withdraw thresholds).
+
+* **Provider**: A provider performs a specific set of *checks* at a certain *cost*. Interaction with a provider is performed by provider-specific *logic*.
+
+* **Program**: An AML helper *program* is given *context* about the current state of an account and the attribute data from a *check* to compute the *outcome*. For example, a *program* may look at the "PEP" field of a KYC check and decide if the outcome is to put the account into ``normal`` or ``held-for-manual-review`` state.
+
+* **Type of operation**: The operation type determines which Taler-specific operation has triggered the KYC requirement. We support four types of operation: withdraw (by customer), deposit (by merchant), P2P receive (by wallet) and (high) wallet balance.
+
+
+451 Response
+^^^^^^^^^^^^
+
+When KYC operations are required, various endpoints may respond with a
+``451 Unavailable for Legal Reasons`` status code and a `KycNeededRedirect`
+body.
+
+ .. ts:def:: KycNeededRedirect
+
+ interface KycNeededRedirect {
+
+ // Numeric `error code <error-codes>` unique to the condition.
+ // Should always be ``TALER_EC_EXCHANGE_GENERIC_KYC_REQUIRED``.
+ code: number;
+
+ // Human-readable description of the error, i.e. "missing parameter", "commitment violation", ...
+ // Should give a human-readable hint about the error's nature. Optional, may change without notice!
+ hint?: string;
+
+ // Public key associated with the account. The client must sign
+ // the initial request for the KYC status using the corresponding
+ // private key. Will be either a reserve public key or a merchant
+ // (instance) public key.
+ account_pub: EddsaPublicKey;
+
+ // Legitimization target that the merchant should
+ // use to check for its KYC status using
+ // the ``/kyc-check/$REQUIREMENT_ROW`` endpoint.
+ requirement_row: Integer;
+
+ }
+
+
+New Endpoints
+^^^^^^^^^^^^^
+
+.. http:get:: /kyc-check/$REQUIREMENT_ROW
+
+ Checks the KYC status of a particular payment target and possibly begins the
+ KYC process. This endpoint is typically used by wallets or merchants that
+ have been told about a KYC requirement and now want to check if the KYC
+ requirement has been fulfilled. Long-polling may be used to instantly
+ observe a change in the KYC requirement status.
+
+ The requirement row of the ``/kyc-check/`` endpoint encodes the
+ legitimization measure's serial number. It is returned in
+ `KycNeededRedirect` responses via the ``requirement_row`` field.
+
+ Given a valid pair of requirement row and account owner signature, the
+ ``/kyc-check/`` endpoint returns either just the KYC status or redirects the
+ client (202) to the next required stage of the KYC process. The redirection
+ must be for an HTTP(S) endpoint to be triggered via a simple HTTP GET. It
+ must always be the same endpoint for the same client, as the wallet/merchant
+ backend are not required to check for changes to this endpoint. Clients
+ that received a 202 status code may repeat the request and use long-polling
+ to detect a change of the HTTP status.
+
+ **Request:**
+
+ *Account-Owner-Signature*: The client must provide Base-32 encoded EdDSA
+ signature with ``$ACCOUNT_PRIV``, affirming the desire to obtain KYC data.
+ Note that this is merely a simple authentication mechanism, the details of
+ the request are not protected by the signature. The ``$ACCOUNT_PRIV``
+ is either the (wallet long-term) reserve private key or the merchant
+ instance private key.
+
+ :query timeout_ms=NUMBER: *Optional.* If specified, the exchange will
+ wait up to ``timeout_ms`` milliseconds if the requirement continues
+ to be mandatory provisioning of KYC data by the client.
+ Ignored if the HTTP status code is already ``200 Ok``. Note that
+ clients cannot long-poll for AML staff actions, so status information
+ about an account being under AML review needs to be requested
+ periodically.
+
+ **Response:**
+
+ :http:statuscode:`200 Ok`:
+ No mandatory KYC actions are required by the client at this time.
+ The client *may* still visit the KYC URL to initiate voluntary checks.
+ The response will be an `AccountKycStatus` object which specifies
+ restrictions that currently apply to the account. If the
+ client attempts to exceed *soft* limits, the status may change
+ to a ``202 Accepted``. Hard limits cannot be lifted by passing KYC checks.
+ :http:statuscode:`202 Accepted`:
+ The account holder performed an operation that would have crossed
+ *soft* limits and must be redirected to the provided location to perform
+ the required KYC checks to satisfy the legal requirements. Afterwards, the
+ ``/kyc-check/`` request should be repeated to check whether the
+ user has completed the process.
+ The response will be an `AccountKycStatus` object.
+ :http:statuscode:`204 No content`:
+ The exchange is not configured to perform KYC and thus
+ the legal requirements are already satisfied.
+ :http:statuscode:`403 Forbidden`:
+ The provided hash does not match the requirement row.
+ :http:statuscode:`404 Not found`:
+ The requirement row is unknown.
+
+ **Details:**
+
+ .. ts:def:: AccountKycStatus
+
+ interface AccountKycStatus {
+
+ // Current time of the exchange, used as part of
+ // what the exchange signs over.
+ now: Timestamp;
+
+ // Current AML state for the target account. True if
+ // operations are not happening due to staff processing
+ // paperwork *or* due to legal requirements (so the
+ // client cannot do anything but wait).
+ //
+ // Note that not every AML staff action may be legally
+ // exposed to the client, so this is merely a hint that
+ // a client should be told that AML staff is currently
+ // reviewing the account. AML staff *may* review
+ // accounts without this flag being set!
+ aml_review: boolean;
+
+ // URL that the user should open in a browser to
+ // proceed with the KYC process (optional if
+ // the status type is ``200 Ok``, mandatory if the
+ // HTTP status is ``202 Accepted``).
+ kyc_url: string;
+
+ // Array with limitations that currently apply to this
+ // account and that may be increased or lifted if the
+ // KYC check is passed.
+ // Note that additional limits *may* exist and not be
+ // communicated to the client. If such limits are
+ // reached, this *may* be indicated by the account
+ // going into ``aml_review`` state. However, it is
+ // also possible that the exchange may legally have
+ // to deny operations without being allowed to provide
+ // any justification.
+ // The limits should be used by the client to
+ // possibly structure their operations (e.g. withdraw
+ // what is possible below the limit, ask the user to
+ // pass KYC checks or withdraw the rest after the time
+ // limit is passed, warn the user to not withdraw too
+ // much or even prevent the user from generating a
+ // request that would cause it to exceed hard limits).
+ limits?: AccountLimit[];
+
+ }
+
+ .. ts:def:: AccountLimit
+
+ interface AccountLimit {
+
+ // Operation that is limited.
+ // Must be one of "WITHDRAW", "DEPOSIT", "P2P-RECEIVE"
+ // or "WALLET-BALANCE".
+ operation_type: string;
+
+ // Timeframe during which the limit applies.
+ timeframe: RelativeTime;
+
+ // Maximum amount allowed during the given timeframe.
+ // Zero if the operation is simply forbidden.
+ threshold: Amount;
+
+ // True if this is a soft limit that could be raised
+ // by passing KYC checks. Clients *may* deliberately
+ // try to cross limits and trigger measures resulting
+ // in 451 responses to begin KYC processes.
+ // Clients that are aware of hard limits *should*
+ // inform users about the hard limit and prevent flows
+ // in the UI that would cause violations of hard limits.
+ soft_limit: boolean;
+ }
+
+
+.. http:get:: /kyc-spa/$TARGET_TOKEN
+.. http:get:: /kyc-spa/$FILENAME
+
+ A set of ``/kyc-spa/$TARGET_TOKEN`` GET endpoints is created per account
+ hash that serves the KYC SPA. This is where the ``/kyc-check/`` endpoint
+ will in principle redirect clients. The KYC SPA will use the
+ ``$TARGET_TOKEN`` of its URL to initialize itself via the
+ ``/kyc-info/$TARGET_TOKEN`` endpoint family. The KYC SPA may download
+ additional resources via ``/kyc-spa/$FILENAME``. The filenames must not
+ match base32-encoded 256-bit values.
+
+.. http:get:: /kyc-info/$TARGET_TOKEN
+
+ A new set of ``/kyc-info/$TARGET_TOKEN`` GET endpoints is created per client
+ account hash to return information about the state of the KYC or AML process
+ to the KYC SPA. The SPA uses this information to show the user an
+ appropriate dialog. The SPA should also long-poll this endpoint for changes
+ to the AML/KYC state. Note that this is a client-facing endpoint, so it will
+ only provide a restricted amount of information to the customer (as some
+ laws may forbid us to inform particular customers about their true status).
+ The endpoint will typically inform the SPA about possible choices to
+ proceed, such as directly uploading files, contacting AML staff, or
+ proceeding with a particular KYC process at an external provider (such as
+ Challenger). If the user chooses to initate a KYC process at an external
+ provider, the SPA must request the respective process to be set-up by the
+ exchange via the ``/kyc-start/`` endpoint.
+
+ **Request**:
+
+ *If-None-Match*: The client MAY provide an ``If-None-Match`` header with
+ an ETag.
+
+ :query timeout_ms=MILLISECONDS: *Optional.* If specified, the exchange
+ will wait up to MILLISECONDS for a change to a more recent legitimization
+ measure before returning a 304 Not Modified status.
+
+ **Response**:
+
+ :http:statuscode:`200 OK`:
+ The body is a `KycProcessClientInformation`.
+
+ *Etag*: Will be set to the serial ID of the measure. Used for long-polling.
+
+ .. ts:def:: KycProcessClientInformation
+
+ interface KycProcessClientInformation {
+
+ // List of requirements.
+ requirements?: { name : KycRequirementInformation};
+
+ // True if the client is expected to eventually satisfy all requirements.
+ // Default (if missing) is false.
+ is_and_combinator?: boolean
+
+ // List of available voluntary checks the client could pay for.
+ // Since **vATTEST**.
+ voluntary_checks?: { name : KycCheckInformation};
+ }
+
+ .. ts:def:: KycRequirementInformation
+
+ interface KycRequirementInformation {
+
+ // Which form should be used? Common values include "INFO"
+ // (to just show the descriptions but allow no action),
+ // "LINK" (to enable the user to obtain a link via
+ // ``/kyc-start/``) or any build-in form name supported
+ // by the SPA.
+ form: string;
+
+ // English description of the requirement.
+ description: string;
+
+ // Map from IETF BCP 47 language tags to localized
+ // description texts.
+ description_i18n ?: { [lang_tag: string]: string };
+
+ // ID of the requirement, useful to construct the
+ // ``/kyc-upload/$ID`` or ``/kyc-start/$ID`` endpoint URLs.
+ // Present if and only if "form" is not "INFO". The
+ // ``$ID`` value may itself contain ``/`` or ``?`` and
+ // basically encode any URL path (and optional arguments).
+ id?: string;
+
+ }
+
+ .. ts:def:: KycCheckInformation
+
+ // Since **vATTEST**.
+ interface KycCheckInformation {
+
+ // How much would this check cost the client?
+ cost: Amount;
+
+ // English description of the check.
+ description: string;
+
+ // Map from IETF BCP 47 language tags to localized
+ // description texts.
+ description_i18n ?: { [lang_tag: string]: string };
+
+ }
+
+ :http:statuscode:`204 No Content`:
+ There are no open KYC requirements or possible voluntary checks
+ the client might perform.
+
+ :http:statuscode:`304 Not Modified`:
+ The KYC requirements did not change.
+
+
+.. http:post:: /kyc-upload/$ID
+
+ The ``/kyc-upload/$ID`` POST endpoint allows the SPA to upload
+ client-provided evidence. The ``$ID`` will be provided as part of the
+ ``/kyc-info`` body. This is for checks of type ``FORM``. In practice,
+ ``$ID`` will encode both the ``$TARGET_TOKEN`` and the index of the selected
+ measure (but this should be irrelevant for the client).
+
+ **Request**:
+
+ Basically oriented along the possible formats of a HTTP form being
+ POSTed. Details will depend on the form. The server will try to decode the
+ uploaded body from whatever format it is provided in.
+
+ **Response**:
+
+ :http:statuscode:`204 No Content`:
+ The information was successfully uploaded. The SPA should fetch
+ an updated ``/kyc-info/``.
+ :http:statuscode:`404 Not Found`:
+ The ``$ID`` is unknown to the exchange.
+ :http:statuscode:`409 Conflict`:
+ The upload conflicts with a previous upload.
+ :http:statuscode:`413 Content Too Large`:
+ The body is too large.
+
+.. http:post:: /kyc-start/$ID
+
+ The ``/kyc-start/$ID`` POST endpoint allows the SPA to set up a new external
+ KYC process. It will return the URL that the client must GET to begin the
+ KYC process. The SPA should probably open this URL in a new window or tab.
+ The ``$ID`` will be provided as part of the ``/kyc-info`` body. In
+ practice, ``$ID`` will encode both the ``$TARGET_TOKEN`` and the index of
+ the selected measure (but this should be irrelevant for the client).
+
+ **Request**:
+
+ Use empty JSON body for now.
+
+ **Response**:
+
+ :http:statuscode:`200 Ok`:
+ The KYC process was successfully initiated. The URL is in a
+ `KycProcessStartInformation` object.
+
+ .. ts:def:: KycProcessStartInformation
+
+ interface KycProcessStartInformation {
+
+ // URL to open.
+ redirect_url: string;
+ }
+
+ :http:statuscode:`404 Not Found`:
+ The ``$ID`` is unknown to the exchange.
+
+ .. note::
+
+ As this endpoint is involved in every KYC check at the beginning, this
+ is also the place where we could integrate the payment process for the KYC fee
+ in the future (since **vATTEST**).
+
+
+.. http:get:: /kyc-proof/$PROVIDER_SECTION?state=$H_PAYTO
+
+ Upon completion of the process at the external KYC provider, the provider
+ must redirect the client (browser) to trigger a GET request to a new
+ ``/kyc-proof/$H_PAYTO/$PROVIDER_SECTION`` endpoint. Once this endpoint is
+ triggered, the exchange will pass the received arguments to the respective
+ logic plugin. The logic plugin will then (asynchronously) update the KYC
+ status of the user. The logic plugin should return a human-readable HTML
+ page with the KYC result to the user. This endpoint deliberately does
+ not use the ``$TARGET_TOKEN`` as the provider should not learn that token.
+
+ This endpoint is thus accessed from the user's browser at the *end* of a KYC
+ process, possibly providing the exchange with additional credentials to
+ obtain the results of the KYC process. Specifically, the URL arguments
+ should provide information to the exchange that allows it to verify that the
+ user has completed the KYC process. The details depend on the logic, which
+ is selected by the "$PROVIDER_SECTION".
+
+ While this is a GET (and thus safe, and idempotent), the operation may
+ actually trigger significant changes in the exchange's state. In
+ particular, it may update the KYC status of a particular payment target.
+
+ **Request:**
+
+ Details on the request depend on the specific KYC logic that was used.
+
+ If the KYC plugin logic is OAuth 2.0, the query parameters are:
+
+ :query code=CODE: OAuth 2.0 code argument.
+ :query state=STATE: OAuth 2.0 state argument with the H_PAYTO.
+
+ .. note::
+
+ Depending on the OAuth variant used, additional
+ query parameters may need to be passed here.
+
+ **Response:**
+
+ Given that the response is returned to a user using a browser and **not** to
+ a Taler wallet, the response format is in human-readable HTML and not in
+ machine-readable JSON.
+
+ :http:statuscode:`302 Found`:
+ The KYC operation succeeded and the
+ payment target is now authorized to transact.
+ The browser is redirected to a human-readable
+ page configured by the exchange operator.
+ :http:statuscode:`401 Unauthorized`:
+ The provided authorization token is invalid.
+ :http:statuscode:`404 Not found`:
+ The payment target is unknown.
+ :http:statuscode:`502 Bad Gateway`:
+ The exchange received an invalid reply from the
+ legitimization service.
+ :http:statuscode:`504 Gateway Timeout`:
+ The exchange did not receive a reply from the legitimization
+ service within a reasonable time period.
+
+
+.. http:get:: /kyc-webhook/$PROVIDER_SECTION/*
+.. http:post:: /kyc-webhook/$PROVIDER_SECTION/*
+.. http:get:: /kyc-webhook/$LOGIC/*
+.. http:post:: /kyc-webhook/$LOGIC/*
+
+ Alternatively, the KYC confirmation may be triggered by a ``/kyc-webhook``
+ request. As KYC **providers** do not necessarily support passing detailed
+ information in the URL arguments, the ``/kyc-webhook`` only needs to specify
+ either the ``PROVIDER_SECTION`` *or* the ``LOGIC`` (the name of the plugin
+ implementing the KYC API). The API-specific webhook logic must then figure
+ out what exactly the webhook is about on its own. The ``/kyc-webhook/``
+ endpoint works for GET or POST, again as details depend on the KYC provider.
+ In contrast to ``kyc-proof``, the response does NOT go to the end-users'
+ browser and should thus only indicate success or failure.
+
+ **Request:**
+
+ Details on the request depend on the specific KYC logic that was used.
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The operation succeeded.
+ :http:statuscode:`404 Not found`:
+ The specified logic is unknown.
+
+
+.. http:post:: /kyc-wallet``
+
+ The ``/wallet-kyc`` POST endpoint allows a wallet to notify an exchange if
+ it will cross a balance threshold. Here, the ``balance`` specified should be
+ the threshold (from the ``wallet_balance_limit_without_kyc`` array) that the
+ wallet would cross, and *not* the *exact* balance of the wallet. The exchange
+ will respond with a wire target UUID. The wallet can then use this UUID to
+ being the KYC process at ``/kyc-check/``. The wallet must only proceed to
+ obtain funds exceeding the threshold after the KYC process has concluded.
+ While wallets could be "hacked" to bypass this measure (we cannot
+ cryptographically enforce this), such modifications are a terms of service
+ violation which may have legal consequences for the user.
+
+ Setup KYC identification for a wallet. Returns the KYC UUID. This endpoint
+ is used by compliant Taler wallets when they are about to hit the balance
+ threshold and thus need to have the customer provide their personal details
+ to the exchange. The wallet is identified by its long-lived reserve public
+ key (which is used for P2P payments, not for withdrawals).
+
+ **Request:**
+
+ The request body must be a `WalletKycRequest` object.
+
+ **Response:**
+
+ :http:statuscode:`204 No Content`:
+ KYC is disabled at this exchange, or the balance is below the
+ threshold that requires KYC, or this wallet already satisfied
+ the KYC check for the given balance.
+ :http:statuscode:`403 Forbidden`:
+ The provided signature is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`451 Unavailable for Legal Reasons`:
+ The wallet must undergo a KYC check. A KYC ID was created.
+ The response will be a `WalletKycUuid` object.
+
+ **Details:**
+
+ .. ts:def:: WalletKycRequest
+
+ interface WalletKycRequest {
+
+ // Balance threshold (not necessarily exact balance)
+ // to be crossed by the wallet that (may) trigger
+ // additional KYC requirements.
+ balance: Amount;
+
+ // EdDSA signature of the wallet affirming the
+ // request, must be of purpose
+ // ``TALER_SIGNATURE_WALLET_ACCOUNT_SETUP``
+ reserve_sig: EddsaSignature;
+
+ // long-term wallet reserve-account
+ // public key used to create the signature.
+ reserve_pub: EddsaPublicKey;
+ }
+
+ .. ts:def:: WalletKycUuid
+
+ interface WalletKycUuid {
+
+ // UUID that the wallet should use when initiating
+ // the KYC check.
+ requirement_row: number;
+
+ // Hash of the payto:// account URI for the wallet.
+ h_payto: PaytoHash;
+
+ }
+
+
+.. http:get:: /aml/$OFFICER_PUB/measures
+
+ To enable the AML staff SPA to give AML staff a choice of possible measures, a
+ new endpoint ``/aml/$OFFICER_PUB/measures`` is added that allows the AML SPA
+ to dynamically GET the list of available measures. It returns a list of known
+ KYC checks (by name) with their descriptions and a list of AML programs with
+ information about the required context.
+
+ **Request**:
+
+ *Taler-AML-Officer-Signature*: The client must provide Base-32 encoded EdDSA
+ signature with ``$OFFICER_PRIV``, affirming the desire to obtain AML data.
+ Note that this is merely a simple authentication mechanism, the details of
+ the request are not protected by the signature.
+
+ **Response**:
+
+ :http:statuscode:`200 Ok`:
+ Information about possible measures is returned in a
+ `AvailableMeasureSummary` object.
+
+ .. ts:def:: AvailableMeasureSummary
+
+ interface AvailableMeasureSummary {
+
+ // Available original measures that can be
+ // triggered directly by default rules.
+ roots: { "$measure_name" : MeasureInformation };
+
+ // Available AML programs.
+ programs: { "$prog_name" : AmlProgramRequirement };
+
+ // Available KYC checks.
+ checks: { "$check_name" : KycCheckInformation };
+
+ }
+
+ .. ts:def:: MeasureInformation
+
+ interface MeasureInformation {
+
+ // Name of a KYC check.
+ check_name: string;
+
+ // Name of an AML program.
+ prog_name: string;
+
+ // Context for the check. Optional.
+ context?: Object;
+
+ }
+
+ .. ts:def:: AmlProgramRequirement
+
+ interface AmlProgramRequirement {
+
+ // Description of what the AML program does.
+ description: string;
+
+ // List of required field names in the context to run this
+ // AML program. SPA must check that the AML staff is providing
+ // adequate CONTEXT when defining a measure using this program.
+ context: string[];
+
+ // List of required attribute names in the
+ // input of this AML program. These attributes
+ // are the minimum that the check must produce
+ // (it may produce more).
+ inputs: string[];
+
+ }
+
+ .. ts:def:: KycCheckInformation
+
+ interface KycCheckInformation {
+
+ // Description of the KYC check. Should be shown
+ // to the AML staff but will also be shown to the
+ // client when they initiate the check in the KYC SPA.
+ description: string;
+ description_i18n: {};
+
+ // Names of the fields that the CONTEXT must provide
+ // as inputs to this check.
+ // SPA must check that the AML staff is providing
+ // adequate CONTEXT when defining a measure using
+ // this check.
+ requires: string[];
+
+ // Names of the attributes the check will output.
+ // SPA must check that the outputs match the
+ // required inputs when combining a KYC check
+ // with an AML program into a measure.
+ outputs: string[];
+
+ // Name of a root measure taken when this check fails.
+ fallback: string;
+ }
+
+.. http:get:: /aml/kyc-statistics/$NAME
+
+ Returns the number of KYC events matching the given
+ event type ``$NAME`` in the specified time range.
+ Note that this query can be slow as the statistics
+ are computed on-demand. (This is OK as such requests
+ should be rare.)
+
+ **Request**:
+
+ *Taler-AML-Officer-Signature*: The client must provide Base-32 encoded EdDSA
+ signature with ``$OFFICER_PRIV``, affirming the desire to obtain AML data.
+ Note that this is merely a simple authentication mechanism, the details of
+ the request are not protected by the signature.
+
+ :query start_date=TIMESTAMP: *Optional*. Specifies the date when to start looking (inclusive). If not given, the start time of the exchange operation is used.
+ :query end_date=TIMESTAMP: *Optional*. Specifies the date when to stop looking (exclusive). If not given, the current date is used.
+
+ **Response**:
+
+ .. ts:def:: EventCounter
+
+ interface EventCounter {
+ // Number of events of the specified type in
+ // the given range.
+ cnt: Integer;
+ }
+
+
+Modifications to existing endpoints
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When withdrawing, the exchange checks if the KYC status is acceptable. If no
+KYC was done and if either the amount withdrawn over a particular timeframe
+exceeds the threshold or the reserve received received a P2P transfer, then a
+``451 Unavailable for Legal Reasons`` is returned which redirects the consumer
+to the new ``/kyc-check/`` handler.
+
+When depositing, the exchange aggregator (!) checks the KYC status and if
+negative, returns an additional information field via the
+``aggregation_transient`` table which is returned via GET ``/deposts/`` to the
+merchant. This way, the merchant learns the ``requirement_row`` needed to
+begin the KYC process (this is independent of the amount) at the new
+``/kyc-check/`` handler.
+
+When merging into a reserve, the KYC status is checked and again the
+merge fails with ``451 Unavailable for Legal Reasons`` to trigger the
+KYC process.
+
+To allow the wallet to do the KYC check if it is about to exceed a set balance
+threshold, we modify the ``/keys`` response to add an optional array
+``wallet_balance_limit_without_kyc`` of threshold amounts is returned.
+Whenever the wallet crosses one of these thresholds for the first time, it
+should trigger the KYC process. If this field is absent, there is no limit.
+If the field is provided, a correct wallet must create a long-term
+account-reserve key pair. This should be the same key that is also used to
+receive wallet-to-wallet payments. Then, *before* a wallet performs an
+operation that would cause it to exceed the balance threshold in terms of
+funds held from a particular exchange, it *should* first request the user to
+complete the KYC process. For that, the wallet should POST to the new
+``/kyc-wallet`` endpoint, providing its long-term reserve-account public key
+and a signature requesting permission to exceed the account limit.
+
+
+Configuration of external KYC providers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For each KYC provider that could contribute to checks the configuration
+specifies a ``$PROVIDER_SECTION`` for each authentication procedure. For each
+(enabled) provider, the exchange has a logic plugin which (asynchronously)
+determines the redirect URL for a given wire target. See below for a
+description of the high-level process for different providers.
+
+ .. code-block:: ini
+
+ [kyc-provider-$PROVIDER_ID]
+
+ # Which plugin is responsible for this provider?
+ LOGIC = PLUGIN_NAME
+
+ # Optional cost, useful if clients want to voluntarily
+ # trigger authentication procedures for attestation.
+ # Since **vATTEST**.
+ COST = EUR:5
+
+ # Plus additional logic-specific options, e.g.:
+ AUTHORIZATION_TOKEN = superdupersecret
+
+ # Other logic-specific internal options (example):
+ FORM_ID = business_legi_form
+
+ # Name of a program to run on the output of the plugin
+ # to convert the result into the desired set of attributes.
+ # The converter must create a log for the system administrator
+ # if the provided inputs do not match expectations.
+ # Note that the converter will be expected to output the
+ # set of attributes listed under the respective ``[kyc-check-*]``
+ # sections. Calling the converter with ``--list-outputs``
+ # should generate a (newline-separated) list of attributes
+ # the converter promises to generate in its JSON output
+ # (when run regularly).
+ CONVERTER = taler-exchange-helper-$NAME
+
+
+Configuration of possible KYC/AML checks
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The configuration specifies a set of possible KYC checks offered by external
+providers, one per configuration section:
+
+ .. code-block:: ini
+
+ [kyc-check-$CHECK_NAME]
+
+ # Which type of check is this? Also determines
+ # the SPA form to show to the user for this check.
+ #
+ # INFO: wait for staff or contact staff out-of band
+ # (only information shown, no SPA action)
+ # FORM: SPA should show an inline (HTML) form
+ # LINK: SPA may start external KYC process or upload
+ #
+ TYPE = INFO|LINK|FORM
+
+ # Optional. Set to YES to allow this check be
+ # done voluntarily by a client (they may then
+ # still have to pay for it). Used to offer the
+ # SPA to display checks even if they are
+ # not required. Default is NO.
+ # Since **vATTEST**.
+ VOLUNTARY = YES/NO
+
+ # Provider id, present only if type is LINK.
+ PROVIDER_ID = id
+
+ # Name of the SPA form, if type is FORM
+ # "INFO" and "LINK" are reserved and must not be used.
+ # The exchange server and the SPA must agree on a list
+ # of supported forms and the resulting attributes.
+ #
+ # The SPA should include a JSON resource file
+ # "forms.json" mapping form names to arrays of
+ # attribute names each form provides.
+ FORM_NAME = name
+
+ # Descriptions to use in the SPA to display the check.
+ DESCRIPTION = "Upload your passport picture"
+ DESCRIPTION_I18N = "{"en":"Upload scan of your passport"}"
+
+ # ';'-separated list of fields that the CONTEXT must
+ # provided as inputs to this check. For example,
+ # for a FORM of type CHOICE, this might state
+ # ``choices: string[];``. The type after the ":"
+ # is for now purely for documentation and is
+ # not checked. However, it may be shown to AML staff
+ # when they configure measures.
+ REQUIRES = requirement;
+
+ # Description of the outputs provided by the check.
+ # Basically, the check's output is expected to
+ # provide the following fields as inputs into
+ # a subsequent AML program.
+ OUTPUTS = business_name street city country registration
+
+ # **original** measure to take if the check fails
+ # (for any reason, e.g. provider or form fail to
+ # satisfy constraints or provider signals user error)
+ # Usually should point to a measure that requests
+ # AML staff to investigate. The fallback measure
+ # context always includes the reasons for the
+ # failure.
+ FALLBACK = MEASURE_NAME
+
+The list of possible FORM names is fixed in the SPA
+for a particular exchange release.
+
+The outcome of *any* check should always be uploaded encrypted into the
+``kyc_attributes`` table. It MUST include an ``expiration_time``.
+
+
+Configuration of legitimization requirement triggers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The configuration also specifies a set of legitimization rules including the
+condition and the measure the condition triggers, one condition per
+configuration section:
+
+ .. code-block:: ini
+
+ [kyc-rule-$RULE_NAME]
+
+ # Operation that triggers this legitimization.
+ # Must be one of WITHDRAW, DEPOSIT, P2P-RECEIVE
+ # or WALLET-BALANCE.
+ OPERATION_TYPE = WITHDRAW
+
+ # Next measures to be performed. The SPA should
+ # display *all* of these measures to the user.
+ # (they have a choice of either which ones, or in
+ # which order they are to be performed).
+ # A special measure "verboten" is used if the
+ # threshold may never be crossed.
+ NEXT_MEASURES = SWISSNESS KYB
+
+ # Context for each of the above measures, optional.
+ MEASURE_CONTEXT_$NAME = CONTEXT
+
+ # "yes" if all REQUIRED_MEASURES will eventually need
+ # to be satisfied, "no" if the user has a choice between
+ # them. Not actually enforced by the exchange, but
+ # primarily used to inform the user whether this is
+ # an "and" or "or". YES for "and".
+ IS_AND_COMBINATOR = YES
+
+ # YES if the rule (specifically, operation type,
+ # threshold, timeframe) and the general nature of
+ # the next measure (verboten or approval required)
+ # should be exposed to the client.
+ # Defaults to NO if not set.
+ EXPOSED = YES
+
+ # Threshold amount above which the legitimization is
+ # triggered. The total must be exceeded in the given
+ # timeframe. Can be 'forever'.
+ THRESHOLD = AMOUNT
+
+ # Timeframe over which the amount to be compared to
+ # the THRESHOLD is calculated.
+ # Ignored for WALLET-BALANCE.
+ TIMEFRAME = DURATION
+
+ # Enabled (default is NO)
+ ENABLED = NO
+
+
+AML programs
+^^^^^^^^^^^^
+
+AML programs are helper programs that can:
+
+* Generate a list of *required* context field names
+ for the helper (introspection!) using the "--required-context"
+ command-line switch. The output should use the same
+ syntax as the REQUIRES clause of ``[kyc-check-]``
+ configuration sections, except that new lines
+ MUST be used to separate fields instead of ";".
+* Generate a list of *required* attribute names
+ for the helper (introspection!) using the "--required-attributes"
+ command-line switch. The output should use the same
+ list of names as the ATTRIBUTES in the
+ ``[kyc-provider-]`` configuration section
+ (but may also include FORM field names).
+* Process an input JSON object of type
+ `AmlProgramInput` into a JSON object of
+ type `AmlProgramOutcome`.
+ This is the default behavior if no command-line switches
+ are provided.
+
+.. ts:def:: AmlProgramInput
+
+ interface AmlProgramInput {
+
+ // JSON object that was provided as
+ // part of the *measure*. This JSON object is
+ // provided under "context" in the main JSON object
+ // input to the AML program. This "context" should
+ // satify both the REQUIRES clause of the respective
+ // check and the output of "--requires" from the
+ // AML program's command-line option.
+ context?: Object;
+
+ // JSON object that captures the
+ // output of a ``[kyc-provider-]`` or (HTML) FORM.
+ // The keys in the JSON object will be the attribute
+ // names and the values must be strings representing
+ // the data. In the case of file uploads, the data
+ // MUST be base64-encoded.
+ attributes: Object;
+
+ // JSON array with the results of historic
+ // AML desisions about the account.
+ // FIXME: review AmlDecisionDetail spec!
+ // (need to enable new outcomes!)
+ aml_history: AmlDecisionDetail[];
+
+ // JSON array with the results of historic
+ // KYC data about the account.
+ // FIXME: review KycDetail spec!
+ // (need to include AmlProgramOutcome!)
+ kyc_history: KycDetail[];
+
+ }
+
+.. ts:def:: AmlProgramOutcome
+
+ interface AmlProgramOutcome {
+
+ // Should the client's account be investigated
+ // by AML staff?
+ // Defaults to false.
+ to_investigate?: boolean;
+
+ // Should the client's account be frozen?
+ // Defaults to false.
+ is_frozen?: boolean;
+
+ // Was the client's account reported to the authorities?
+ // Defaults to false.
+ is_reported?: boolean;
+
+ // Free-form properties about the account.
+ // Can be used to store properties such as PEP,
+ // risk category, type of business, hits on
+ // sanctions lists, etc.
+ properties?: AccountProperties;
+
+ // Types of events to add to the KYC events table.
+ // (for statistics).
+ events?: string[];
+
+ // When does the outcome expire?
+ expiration_time: Timestamp;
+
+ // Name of the measure to apply the outcome expires.
+ // If not set, we revert to the default set
+ // of rules (and the default account state).
+ successor_measure?: string;
+
+ // Array of KYC rules to apply. Note that this
+ // array overrides *all* of the default rules.
+ // Thus, if the array does not have an entry for
+ // a particular operation, there would be
+ // no thresholds for that operation!
+ rules: KycRule[];
+
+ // Custom measures that KYC rules may refer to.
+ custom_measures?: { "name" : MeasureInformation };
+
+ }
+
+.. ts:def:: KycRule
+
+ interface KycRule {
+
+ // Type of operation to which the rule applies.
+ operation_type: string;
+
+ // Measure to be taken if the given
+ // threshold is crossed over the given timeframe.
+ threshold: Amount;
+
+ // Over which duration should the threshold be
+ // computed.
+ timeframe: RelativeTime;
+
+ // Array of names of measures to apply.
+ // Names listed can be original measures or
+ // custom measures from the `AmlProgramOutcome`.
+ // A special measure "verboten" is used if the
+ // threshold may never be crossed.
+ measures: string[];
+
+ // True if the rule (specifically, operation_type,
+ // threshold, timeframe) and the general nature of
+ // the measures (verboten or approval required)
+ // should be exposed to the client.
+ // Defaults to "false" if not set.
+ exposed?: boolean;
+
+ // True if all the measures will eventually need to
+ // be satisfied, false if any of the measures should
+ // do.
+ // Default (if missing) is false.
+ is_and_combinator?: boolean;
+ }
+
+If the AML program fails (exits with a failure code or
+does not provide well-formed JSON output) the AML/KYC
+process continues with the FALLBACK measure. This should
+usually be one that asks AML staff to contact the
+systems administrator.
+
+AML programs are listed in the configuration file, one program per section:
+
+ .. code-block:: ini
+
+ [aml-program-$PROG_NAME]
+
+ # Program to run.
+ COMMAND = taler-helper-aml-pep
+
+ # Human-readable description of what this
+ # AML helper program will do. Used to show
+ # to the AML staff.
+ DESCRIPTION = "check if the customer is a PEP"
+
+ # True if this AML program is enabled (and thus can be
+ # used in measures and exposed to AML staff).
+ # Optional, default is NO.
+ ENABLED = YES
+
+ # **original** measure to take if COMMAND fails
+ # Usually points to a measure that asks AML staff
+ # to contact the systems administrator. The fallback measure
+ # context always includes the reasons for the
+ # failure.
+ FALLBACK = MEASURE_NAME
+
+
+Configuration of measures
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Finally, the configuration specifies a set of
+**original** *measures* one per configuration section:
+
+ .. code-block:: ini
+
+ [kyc-measure-$MEASURE_NAME]
+
+ # Possible check for this measure. Optional.
+ # If not given, PROGRAM should be run immediately
+ # (on an empty set of attributes).
+ CHECK_NAME = IB_FORM
+
+ # Context for the check. The context can be
+ # just an empty JSON object if there is none.
+ CONTEXT = {"choices":["individual","business"]}
+
+ # Program to run on the context and check data to
+ # determine the outcome and next measure.
+ PROGRAM = taler-aml-program
+
+If no ``CHECK_NAME`` is provided at all, the AML ``PROGRAM`` is to be run
+immediately. This is useful if no client-interaction is required to arrive at
+a decision.
+
+.. note::
+
+ The list of *measures* is not complete: AML staff may freely define new
+ measures dynamically, usually by selecting checks, an AML program, and
+ providing context.
+
+
+Sanity checking
+^^^^^^^^^^^^^^^
+
+On start-up, ``taler-exchange-httpd`` should sanity-check its
+configuration. Specifically, it should validate that for all AML programs the
+input requirements (attributes and context) are claimed to be satisfied by the
+respective checks that may trigger those programs, and similarly that for all
+checks the original measures satisfy the context requirements for their KYC
+checks.
+
+As a result, any component (AML program, form or external check) is warranted
+to be always called with the declared required inputs. Furthermore, we can
+detect if a component fails to produce the required output and the
+configuration contains (presumably safe) FALLBACKs to address this case. The
+exchange *MUST* detect circular failures, like when a FALLBACK triggers a
+measure that itself immediately triggers again the same FALLBACK.
+
+
+Exchange database schema
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+We introduce a new ``wire_targets`` table into the exchange database. This
+table is referenced as the source or destination of payments (regular deposits
+and also P2P payments). A positive side-effect is that we reduce duplication
+in the ``reserves_in``, ``wire_out`` and ``deposits`` tables as they can
+reference this table.
+
+We introduce a new ``legitimization_processes`` table that tracks the status
+of a legitimization process at a provider, including the configuration section
+name, the user/account name at the provider, and some legitimization
+identifier for the process at the provider. In this table, we additionally
+store information related to the KYC status of the underlying payto://-URI, in
+particular when the KYC expires (0 if it was never done).
+
+Finally, we introduce a new ``legitimization_requirements`` table that
+contains a list of checks required for a particular wire target. When KYC is
+triggered (say when some endpoint returns an HTTP status code of 451) a
+new requirement is first put into the requirements table. Then, when the
+client identifies as business or individual the specific legitimization
+process is started. When the taler-exchange-aggregator triggers a KYC check
+the merchant can observe this when a 202 (Accepted) status code is returned
+on GET ``/deposits/`` with the respective legitimization requirement row.
+
+
+.. sourcecode:: sql
+
+ CREATE TABLE wire_targets
+ (wire_target_serial_id BIGSERIAL UNIQUE
+ ,h_payto BYTEA NOT NULL CHECK (LENGTH(h_payto)=64),
+ ,target_token BYTEA UNIQUE CHECK (LENGTH(target_token)=32)
+ ,target_pub BYTEA CHECK (LENGTH(target_pub)=32)
+ ,payto_uri STRING NOT NULL
+ ,PRIMARY KEY (h_payto,target_pub)
+ )
+ PARTITION BY HASH (h_payto);
+
+ COMMENT ON TABLE wire_targets
+ IS 'All recipients of money via the exchange';
+ COMMENT ON COLUMN wire_targets.payto_uri
+ IS 'Can be a regular bank account, or also be a URI identifying a reserve-account (for P2P payments)';
+ COMMENT ON COLUMN wire_targets.h_payto
+ IS 'Unsalted hash of payto_uri';
+ COMMENT ON COLUMN wire_targets.target_token
+ IS 'high-entropy random value that uniquely identifies the wire target and is used as a token to authorize access to the KYC process (without requiring a signature by target_priv); NULL if KYC is not allowed for the account (legacy)';
+ COMMENT ON COLUMN wire_targets.target_pub
+ IS 'Public key (reserve_pub or merchant_pub) associated with the account; NULL if KYC is not allowed for the account (legacy)';
+
+ CREATE TABLE IF NOT EXISTS legitimization_measures
+ (legitimization_measure_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY
+ ,target_token BYTEA NOT NULL UNIQUE CHECK (LENGTH(target_token)=32)
+ REFERENCES wire_targets (target_token)
+ ,start_time INT8 NOT NULL
+ ,jmeasures VARCHAR[] NOT NULL
+ ,is_finished BOOL NOT NULL DEFAULT(FALSE)
+ )
+ PARTITION BY HASH (h_payto);
+
+ COMMENT ON COLUMN legitimization_requirements.target_token
+ IS 'Used to uniquely identify the account and as a symmetric access control mechanism for the SPA';
+ COMMENT ON COLUMN legitimization_requirements.start_time
+ IS 'Time when the measure was triggered (by decision or rule)';
+ COMMENT ON COLUMN legitimization_requirements.jmeasures
+ IS 'JSON object of type LegitimizationMeasures with KYC/AML measures for the account encoded';
+ COMMENT ON COLUMN legitimization_requirements.is_finished
+ IS 'Set to TRUE if this set of measures was processed; used to avoid indexing measures that are done';
+
+ CREATE INDEX ON legitimization_measures (target_token)
+ WHERE NOT finished;
+
+ CREATE TABLE legitimization_outcomes
+ (outcome_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY
+ ,h_payto BYTEA CHECK (LENGTH(h_payto)=32)
+ REFERENCES wire_targets (h_payto)
+ ,decision_time INT8 NOT NULL DEFAULT(0)
+ ,expiration_time INT8 NOT NULL DEFAULT(0)
+ ,jproperties TEXT,
+ ,to_investigate BOOL NOT NULL
+ ,is_frozen BOOL NOT NULL
+ ,is_reported BOOL NOT NULL
+ ,is_active BOOL NOT NULL DEFAULT(TRUE)
+ ,jnew_rules NOT NULL TEXT
+ )
+ PARTITION BY HASH (h_payto);
+
+ COMMENT ON TABLE legitimization_outcomes
+ IS 'Outcomes can come from AML programs';
+ COMMENT ON COLUMN legitimization_outcomes.h_payto
+ IS 'hash of the payto://-URI this outcome is about';
+ COMMENT ON COLUMN legitimization_outcomes.decision_time
+ IS 'when was this outcome decided';
+ COMMENT ON COLUMN legitimization_outcomes.expiration_time
+ IS 'time when the decision expires and the expiration new_rules should be applied';
+ COMMENT ON COLUMN legitimization_outcomes.jproperties
+ IS 'JSON object of type AccountProperties, such as PEP status, business domain, risk assessment, etc.';
+ COMMENT ON COLUMN legitimization_outcomes.to_investigate
+ IS 'AML staff should investigate the activity of this account';
+ COMMENT ON COLUMN legitimization_outcomes.is_frozen
+ IS 'Transactions with this account should be held (until expiration data or AML staff action)';
+ COMMENT ON COLUMN legitimization_outcomes.is_reported
+ IS 'Set to TRUE if the activity of the account was reported to authorities';
+ COMMENT ON COLUMN legitimization_outcomes.is_active
+ IS 'TRUE if this is the current authoritative legitimization outcome';
+ COMMENT ON COLUMN legitimization_outcomes.jnew_rules
+ IS 'JSON object of type LegitimizationRules with rules to apply to the various operation types for this account; all KYC checks should first check if active new rules for a given account exist in this table (and apply specified measures); if not, it should check the default rules to decide if a measure is required';
+
+ CREATE INDEX legitimization_outcomes_active
+ ON legitimization_outcomes(h_payto)
+ WHERE is_active;
+
+ CREATE TABLE kyc_setups
+ (kyc_setup_serial_id BIGSERIAL UNIQUE
+ ,h_payto BYTEA NOT NULL CHECK (LENGTH(h_payto)=64)
+ REFERENCES wire_targets (h_payto)
+ ,start_time INT8 NOT NULL
+ ,expiration_time INT8 NOT NULL DEFAULT (0)
+ ,legitimization_measure_serial_id BIGINT
+ REFERENCES legitimization_measures (legitimization_measure_serial_id)
+ ,measure_index INT8
+ ,provider_section VARCHAR NOT NULL
+ ,provider_user_id VARCHAR DEFAULT NULL
+ ,provider_legitimization_id VARCHAR DEFAULT NULL
+ ,redirect_url TEXT DEFAULT NULL
+ ,finished BOOLEAN DEFAULT (FALSE)
+ )
+ PARTITION BY HASH (h_payto);
+
+ COMMENT ON TABLE kyc_setups
+ IS 'here we track KYC processes we initiated with external providers; the main reason is so that we do not initiate a second process when an equivalent one is still active; note that h_payto, provider_section, jcontext must match and the process must not be finished or expired for an existing redirect_url to be re-used; given that clients may voluntarily initiate KYC processes, there may not always be a legitimization_measure that triggered the setup';
+ COMMENT ON COLUMN kyc_setups.h_payto
+ IS 'foreign key linking the entry to the wire_targets table, NOT a primary key (multiple KYC setups are possible per wire target)';
+ COMMENT ON COLUMN kyc_setups.start_time
+ IS 'when was the legitimization process initiated';
+ COMMENT ON COLUMN kyc_setups.expiration_time
+ IS 'when does the process expire (and needs to be manually set up again)';
+ COMMENT ON COLUMN kyc_setups.measure_index
+ IS 'index of the measure in legitimization_measures that was selected for this KYC setup; NULL if legitimization_measure_serial_id is NULL; enables determination of the context data provided to the external process';
+ COMMENT ON COLUMN kyc_setups.provider_section
+ IS 'Configuration file section with details about this provider';
+ COMMENT ON COLUMN kyc_setups.provider_user_id
+ IS 'Identifier for the user at the provider that was used for the legitimization. NULL if provider is unaware.';
+ COMMENT ON COLUMN kyc_setups.provider_legitimization_id
+ IS 'Identifier for the specific legitimization process at the provider. NULL if legitimization was not started.';
+ COMMENT ON COLUMN kyc_setups.legitimization_measure_serial_id
+ IS 'measure that enabled this setup, NULL if client voluntarily initiated the process';
+ COMMENT ON COLUMN kyc_setups.redirect_url
+ IS 'Where the user should be redirected for this external KYC process';
+ COMMENT ON COLUMN kyc_setups.finished
+ IS 'set to TRUE when the specific legitimization process is finished';
+
+ CREATE TABLE kyc_attributes
+ (kyc_attributes_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY
+ ,h_payto BYTEA PRIMARY KEY CHECK (LENGTH(h_payto)=32)
+ REFERENCES wire_targets (h_payto)
+ ,kyc_prox BYTEA NOT NULL CHECK (LENGTH(kyc_prox)=32)
+ ,kyc_setup_serial_id INT8 NOT NULL
+ REFERENCES kyc_setups (kyc_setup_serial_id)
+ ,collection_time INT8 NOT NULL
+ ,expiration_time INT8 NOT NULL
+ ,trigger_outcome_serial INT8 NOT NULL
+ REFERENCES legitimization_outcomes(outcome_serial_id)
+ ,encrypted_attributes BYTEA NOT NULL
+ ) PARTITION BY HASH (h_payto);
+
+ COMMENT ON COLUMN kyc_attributes.h_payto
+ IS 'identifies the account this is about';
+ COMMENT ON COLUMN kyc_attributes.kyc_prox
+ IS 'for proximity search on encrypted data';
+ COMMENT ON COLUMN kyc_attributes.kyc_setup_serial_id
+ IS 'serial ID of the KYC setup that resulted in these attributes';
+ COMMENT ON COLUMN kyc_attributes.collection_time
+ IS 'when were these attributes collected';
+ COMMENT ON COLUMN kyc_attributes.expiration_time
+ IS 'when are these attributes expected to expire';
+ COMMENT ON COLUMN kyc_attributes.trigger_outcome_serial
+ IS 'ID of the outcome that was returned by the AML program based on the KYC data collected';
+ COMMENT ON COLUMN kyc_attributes.encrypted_attributes
+ IS 'encrypted JSON object with the attribute data the check provided';
+
+ CREATE TABLE aml_history
+ (aml_history_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY
+ ,h_payto BYTEA CHECK (LENGTH(h_payto)=32)
+ REFERENCES wire_targets (h_payto)
+ ,legitimization_outcome INT8 NOT NULL
+ REFERENCES legitimization_outcomes (outcome_serial_id)
+ ,justification TEXT NOT NULL
+ ,decider_pub BYTEA CHECK (LENGTH(decider_pub)=32)
+ ,decider_sig BYTEA CHECK (LENGTH(decider_sig)=64);
+
+ COMMENT ON TABLE aml_history
+ IS 'Records decisions by AML staff with the respective signature and free-form justification.';
+ COMMENT ON COLUMN aml_history.legitimization_outcome
+ IS 'Actual outcome for the account (included in what decider_sig signs over)';
+ COMMENT ON COLUMN aml_history.decider_sig
+ IS 'Signature key of the staff member affirming the AML decision; of type AML_DECISION';
+
+ CREATE TABLE kyc_events
+ (event_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY
+ ,event_timestamp INT8 NOT NULL
+ ,event_type TEXT NOT NULL);
+
+ COMMENT ON TABLE kyc_events
+ IS 'Records of key events for statistics. Populated via triggers.';
+ COMMENT ON COLUMN kyc_events.event_type
+ IS 'Name of the event, such as account-open or sar-filed';
+
+ CREATE INDEX kyc_event_index
+ ON kyc_events(event_type,event_timestamp);
+
+
+The ``jmeasures`` JSON in the ``legitimization_measures``
+table has is of type `LegitimizationMeasures`:
+
+.. ts:def:: LegitimizationMeasures
+
+ interface LegitimizationMeasures {
+
+ // Array of legitimization measures that
+ // are to be applied.
+ measures: MeasureInformation[];
+
+ // True if the client is expected to eventually satisfy all requirements.
+ // Default (if missing) is false.
+ is_and_combinator?: boolean;
+ }
+
+
+The ``jnew_rules`` JSON in the ``legitimization_outcomes``
+table has is of type `LegitimizationRules`:
+
+.. ts:def:: LegitimizationRules
+
+ interface LegitimizationRules {
+
+ // Measure to apply when the expiration time is
+ // reached. If not set, we refer to the default
+ // set of rules (and the default account state).
+ successor_measure?: string;
+
+ // Legitimization rules that are to be applied
+ // to this account.
+ rules: KycRule[];
+
+ // Custom measures that KYC rules may refer to.
+ custom_measures: { "name" : MeasureInformation };
+ }
+
+
+The ``jproperties`` JSON in the ``legitimization_outcomes`` table has is of
+type `AccountProperties`. All fields in this object are optional. The actual
+properties collected depend fully on the discretion of the exchange operator;
+however, some common fields are standardized and thus described here.
+
+.. ts:def:: AccountProperties
+
+ interface AccountProperties {
+
+ // True if this is a politically exposed account.
+ // Rules for classifying accounts as politically
+ // exposed are country-dependent.
+ pep?: boolean;
+
+ // True if this is a sanctioned account.
+ // Rules for classifying accounts as sanctioned
+ // are country-dependent.
+ sanctioned?: boolean;
+
+ // True if this is a high-risk account.
+ // Rules for classifying accounts as at-risk
+ // are exchange operator-dependent.
+ high_risk?: boolean;
+
+ // Business domain of the account owner.
+ // The list of possible business domains is
+ // operator- or country-dependent.
+ business_domain?: string;
+
+ }
+
+
+
+KYC forms
+^^^^^^^^^
+
+The KYC SPA run by clients needs to support three TYPEs of checks. INFO is
+only about displaying the provided information, LINK is about setting up an
+exteral KYC check and redirecting there. FORM is about displaying a particular
+(HTML) form to the user and POSTing the entered information directly with the
+exchange. Here we describe the forms that must be supported:
+
+* CHOICE: Asks the client a multiple-choice question.
+ The context must include "choices: string[]" with
+ a list of choices to show. Used, for example, to
+ ask a client if they are an individual or a business.
+ The resulting HTML FORM field name must be
+ "choice" and it must be mapped to strings from the
+ choices list.
+* UPLOAD: Asks the client to upload a single file.
+ The context may include "extensions: string[]" with
+ a list of allowed file extensions the client's file
+ must end with (e.g. "png", "pdf", "gif"). In the
+ absence of this context, any file may be uploaded.
+ The context may also include "size_limit: Integer" with
+ the maximum file size in bytes that can be uploaded.
+ The resulting HTML FORM must have two fields,
+ "filename" and "filedata". "filename" must be
+ set to the basename of the original file (to the
+ extend that it is available), and "filedata"
+ to the base64-encoding of the uploaded data.
+
+As with other SPA checks, the KYC form should also show
+the description of the check.
+
+
+Merchant modifications
+^^^^^^^^^^^^^^^^^^^^^^
+
+A new setting is required where the merchant backend can be configured for a
+business (default) or individual.
+
+We introduce new ``kyc_ok``, ``aml_decision``, ``kyc_timestamp`` and
+``exchange_kyc_serial`` fields into a new table ``merchant_kyc`` with primary
+keys ``exchange_url`` and ``account_serial``. This status is updated whenever
+a deposit is created or tracked, or whenever the mechant backend receives a
+``/kyc-check/`` response from the exchange. Initially,
+``exchange_kyc_serial`` is zero, indicating that the merchant has not yet made
+any deposits and thus does not have an account at the exchange.
+
+A new private endpoint ``/kyc`` is introduced which allows frontends to
+request the ``/kyc`` status of any configured account (including with long
+polling). If the KYC status is negative or the ``kyc_timestamp`` not recent
+(say older than one month), the merchant backend will re-check the KYC status
+at the exchange (and update its cached status). The endpoint then returns
+either that the KYC is OK, or information (same as from the exchange endpoint)
+to begin the KYC process.
+
+The merchant backend uses the new field to remember that a KYC is pending
+(after detection in ``taler-merchant-depositcheck``) and the SPA then shows a
+notification whenever the staff is logged in to the system. The notification
+can be hidden for the current day (remembered in local storage).
+
+The notification links to a (new) KYC status page. When opened, the KYC SPA
+first re-checks the KYC status with the exchange. If the KYC is still
+unfinished, that SPA will show forms, links or contact information to begin
+the KYC process (for example, redirecting to the OAuth 2.0 login page of the
+legitimization resource server), otherwise it shows that the KYC process is
+done. If the KYC is unfinished, the merchant SPA should use long-polling on
+the KYC status on this page to ensure it is always up-to-date, and change to
+``KYC satisfied`` should the long-poller return with positive news.
+
+ ..note::
+
+ Semi-related: The TMH_setup_wire_account() is changed to use
+ 128-bit salt values (to keep ``deposits`` table small) and checks for salt
+ to be well-formed should be added "everywhere".
+
+
+
+Bank requirements
+^^^^^^^^^^^^^^^^^
+
+The exchange primarily requires a KYC provider to be operated by the
+bank that offers an endpoint for with an API implemented by one of
+the logic plugins (and the respective legitimization configuration).
+
+
+Logic plugins
+^^^^^^^^^^^^^
+
+The ``$PROVIDER_SECTION`` is based on the name of the configuration section,
+not on the name of the logic plugin (that we call ``$LOGIC``). Using the
+configuration section, the exchange then determines the logic plugin to use.
+
+This section describes the general API for all of the supported KYC providers,
+as well as some details of how this general API could be implemented by the
+logic for different APIs.
+
+
+General KYC Logic Plugin API
+----------------------------
+
+This section provides a sketch of the proposed API for the KYC logic plugins.
+
+* initiation of KYC check (``kyc-check``):
+
+ - inputs:
+ + provider_section (for additional configuration)
+ + h_payto
+ - outputs:
+ + success/provider-failure
+ + redirect URL (or NULL)
+ + provider_user_id (or NULL)
+ + provider_legitimization_id (or NULL)
+
+* KYC status check (``kyc-proof``):
+
+ - inputs:
+ + provider_section (for additional configuration)
+ + h_payto
+ + provider_user_id (or NULL)
+ + provider_legitimization_id (or NULL)
+ - outputs:
+ + success/pending/user-aborted/user-failure/provider-failure status code
+ + HTML response for end-user
+
+* Webhook notification handler (``kyc-webhook``):
+
+ - inputs:
+ + HTTP method (GET/POST)
+ + rest of URL (after provider_section)
+ + HTTP body (if applicable!)
+ - outputs:
+ + success/pending/user-aborted/user-failure/provider-failure status code
+ + h_payto (for DB status update)
+ + HTTP response to be returned to KYC provider
+
+The plugins do not directly interact with the database, the caller sets the
+expiration on ``success`` and also updates ``provider_user_id`` and
+``provider_legitimization_id`` in the tables as required.
+
+
+For the webhook, we need a way to lookup ``h_payto`` by other data, so the
+KYC logic plugin API should be provided a method lookup with:
+
+ - inputs:
+ + ``provider_section``
+ + ``provider_legitimization_id``
+ - outputs:
+ + ``h_payto``
+ + ``legitimization_process_row``
+
+
+OAuth 2.0 specifics
+-------------------
+
+In terms of configuration, the OAuth 2.0 logic requires the respective client
+credentials to be configured apriori to enable access to the legitimization
+service.
+
+For the ``/kyc-check/`` endpoint, the OAuth 2.0 logic may need to create and
+store a nonce to be used during ``/kyc-proof/``, depending on the OAuth
+variant used. This may require another exchange table. The OAuth 2.0 process
+must then be set up to end at the new ``/kyc-proof/$PROVIDER_ID/`` endpoint.
+
+This ``/kyc-proof/oauth2/`` endpoint must query the OAuth 2.0 server using the
+``code`` argument provided as a query parameter. Based on the result, it then
+updates the KYC table of the exchange with the legitimization status and
+returns a human-readable KYC status page.
+
+The ``/kyc-webhook/`` is not applicable.
+
+
+Persona specifics
+-----------------
+
+We would use the hosted flow. Endpoints return a ``request-id``, which we should
+log for diagnosis.
+
+For ``/kyc-check/``:
+
+* Post to ``/api/v1/accounts`` using ``reference-id`` set to our ``h_payto``.
+ Returns ``id`` (account_id).
+
+* Create ``/verify`` endpoint using ``template-id`` (from configuration),
+ and ``account_id`` (from previous step) and a ``reference-id`` (use
+ the ``legitimization_serial_id`` for the new process). Set
+ ``redirect-uri`` to ``/kyc-proof/$PROVIDER_ID/``. However, we cannot
+ rely on the user clicking this, so we must also configure a webhook.
+ The request returns a '``verification-id``. That we store under
+ the ``provider_legitimization_id`` in the database.
+
+For ``/kyc-proof/``:
+
+* Use the ``/api/v1/verifications`` endpoint to get the verification
+ status. Requires the ``verification-id`` from the previous step.
+ Results include: created/pending/completed/expired (aborted)/failed.
+
+For ``/kyc-webhook/``:
+
+* The webhook is authenticated using a shared secret, which should
+ be in the configuration. So all we should have to do is parse
+ the POSTed body to find the status and the ``verification-id`` to
+ lookup ``h_payto`` and return the result.
+
+
+KYC AID specifics
+-----------------
+
+For ``/kyc-check/``:
+
+* Post to ``/applicants`` with a type (person or company) to
+ obtain ``applicant_id``. Store that under ``provider_user_id``.
+ ISSUE: *we* need to get the company_name, business_activity_id
+ and registration_country before this somehow!
+
+* start with create form URL ``/forms/$FORM_ID/urls``
+ providing our ``h_payto`` as the ``external_applicant_id``,
+ using the ``applicant_id`` from above,
+ and the ``/kyc-proof/$PROVIDER_ID`` for the ``redirect_url``.
+
+* redirect customer to the ``form_url``,
+ store the ``verification_id`` under ``provider_legitimization_id``
+ in the database.
+
+For ``/kyc-proof/``:
+
+* Not needed, just return an error.
+
+For ``/kyc-webhook/``:
+
+* For security, we should probably simply trigger the GET on
+ ``/verifications/{verification_id}`` to not trust an unsigned POST
+ to tell us anything for sure. The result is then returned.
+
+
+Types of KYC events
+^^^^^^^^^^^^^^^^^^^
+
+The ``/aml/kyc-statistics`` endpoint exposes statistics
+for various KYC event types.
+
+We will initially support the use of the following types
+of KYC events in the SPA (and have a dialog to show the
+total number of any of these for any specified time range):
+
+* account-open
+* account-closed
+* voluntary-sar
+* mandatory-sar
+* pep-started
+* pep-ended
+* risky-started
+* risky-ended
+* account-frozen
+* account-unfrozen
+
+Based on these, the SPA should also be albe to show active
+statistics (for any given timestamp) on the total number of:
+
+* open accounts
+* frozen accounts
+* high-risk accounts
+* PEPs served
+
+.. note::
+
+ This can be done by simply running the queries with
+ a start time of zero and subtracting.
+
+
+Alternatives
+============
+
+We could also store the access token (returned by OAuth 2.0), but that seems
+slightly more dangerous and given the close business relationship is
+unnecessary. Furthermore, not all APIs offer this.
+
+We could extend the KYC logic API to return key attributes about the user
+(such as legal name, phone number, address, etc.) which we could then sign and
+return to the user. This would be useful in P2P payments to identify the
+origin of an invoice. However, we might want to be careful to not disclose
+the key attributes via the API by accident. This could likely be done by
+limiting access to the respective endpoint to messages with a signature by the
+reserve private key (which is the only case where we care to certify things
+anyway).
+
+
+Drawbacks
+=========
+
+
+Discussion / Q&A
+================
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/024-age-restriction.rst b/design-documents/024-age-restriction.rst
new file mode 100644
index 00000000..0445aa6d
--- /dev/null
+++ b/design-documents/024-age-restriction.rst
@@ -0,0 +1,830 @@
+DD 24: Anonymous Age Restriction Extension
+##########################################
+
+Summary
+=======
+
+This document presents and discusses an extension to GNU Taler that provides
+anonymous age-restriction.
+
+Motivation
+==========
+
+Merchants are legally obliged to perform age verification of customers when
+they buy certain goods and services. Current mechanisms for age verification
+are either ID-based or require the usage of credit/debit cards. In all cases
+sensitive private information is disclosed.
+
+We want to offer a better mechanism for age-restriction with GNU Taler that
+
+* ensures anonymity and unlinkability of purchases
+* can be set to particular age groups by parents/wardens at withdrawal
+* is bound to particular coins/tokens
+* can be verified by the merchant at purchase time
+* persists even after refresh
+
+The mechanism is presented as an 'extension' to GNU Taler, that is, as an
+optional feature that can be switched on by the exchange operator.
+
+Requirements
+============
+
+* legal requirements for merchants must allow for this kind of mechanism
+
+
+Proposed Solution
+=================
+
+We propose an extension to GNU Taler for age-restriction that can be enabled by
+an Exchange¹).
+
+Once enabled, coins with age restrictions can be withdrawn by parents/warden
+who can choose to **commit** the coins to a certain maximum age out of a
+predefined list of age groups.
+
+The minors/wards receive those coins and can now **attest** a required minimum
+age (provided that age is less or equal to the committed age of the coins) to
+merchants, who can **verify** the minimum age.
+
+For the rest values (change) after an transaction, the minor/ward can
+**derive** new age-restricted coins. The exchange can **compare** the equality
+of the age-restriction of the old coin with the new coin (in a zero-knowledge
+protocol, that gives the minor/ward a 1/κ chance to raise the minimum age for
+the new coin).
+
+The proposed solution maintains the guarantees of GNU Taler with respect to
+anonymity and unlinkability. We have published a paper
+`Zero Knowledge Age Restriction for GNU Taler <https://link.springer.com/chapter/10.1007/978-3-031-17140-6_6>`_
+with the details.
+
+¹) Once the feature is enabled and the age groups are defined, the exchange has
+to stick to that decision until the support for age restriction is disabled.
+We might reconsider this design decision at some point.
+
+
+Main ideas and building blocks
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The main ideas are as follows:
+
+#. The exchange defines and publishes M+1 different *age groups* of increasing
+ order: :math:`0 < a_1 < \ldots < a_M` with :math:`a_i \in \mathbb{N}`. The
+ zeroth age group is :math:`\{0,\ldots,a_1-1\}`.
+
+#. An **unrestricted age commitment** is defined as a vector of length M of
+ pairs of Edx25519_ public and private keys on Curve25519. In other words: one
+ key pair for each age group after the zeroth: :math:`\bigl\langle (q_1,
+ p_1), \ldots, (q_M, p_M) \bigr\rangle`. Here, :math:`q_i` are the public keys
+ (mnemonic: **q-mitments**), :math:`p_i` are the private keys.
+
+#. A **restricted age commitment** *to age group m* is derived from an
+ unrestricted age commitment by removing all private keys for
+ indices larger than m: :math:`\bigl\langle (q_1, p_1), \ldots, (q_m, p_m),
+ \, (q_{m+1}, \perp), \ldots, (q_M, \perp )\bigr\rangle`. F.e. if *none* of
+ the private keys is provided, the age commitment would be restricted to the
+ zeroth age group.
+
+#. The act of restricting an unrestricted age commitment is performed by the
+ parent/ward.
+
+#. An *age commitment* (without prefix) is just the vector of public keys:
+ :math:`\vec{Q} := \langle q_1, \ldots, q_M \rangle`. Note that from
+ just the age commitment one can not deduce if it originated from an
+ unrestricted or restricted one (and what age).
+
+#. An *attestation of age group k* is essentially the signature to any message
+ with the private key for slot k, if the corresponding private key is
+ available in a restricted age commitment. (Unrestricted age commitments can
+ attest for any age group).
+
+#. An age commitment is *bound to a particular coin* by incorporating the
+ SHA256 hash value of the age commitment (i.e. the M public keys) into the
+ signature of the coin. So instead of signing :math:`\text{FDH}_N(C_p)` with
+ the RSA private key of a denomination with support for age restriction, we
+ sign :math:`\text{FDH}_N(C_p, h_Q)`. Here, :math:`C_p` is the EdDSA public
+ key of a coin and :math:`h_Q` is the hash of the age commitment :math:`\vec{Q}`.
+ **Note:** A coin with age restriction can only be validated when both, the
+ public key of the coin itself **and** the hash of the age commitment, are
+ present. This needs to be supported in each subsystem: Exchange, Wallet and
+ Merchant.
+
+
+TODO: Summarize the design based on the five functions ``Commit()``,
+``Attest()``, ``Verify()``, ``Derive()``, ``Compare()``, once the paper from
+Özgür and Christian is published.
+
+Changes in the Exchange API
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The necessary changes in the exchange involve
+
+* indication of support for age restriction as an extension
+* modification of the refresh protocol (both, commit and reveal phase)
+* modification of the deposit protocol
+
+
+Extension for age restriction
+-----------------------------
+
+.. note::
+
+ Registering an extension is defined in
+ :doc:`design document 006 ― Extensions <006-extensions>`.
+
+
+The exchange indicates support for age-restriction in response to ``/keys`` by
+registering the extension ``age_restriction`` with a value type
+``ExtensionAgeRestriction``:
+
+.. ts:def:: ExtensionAgeRestriction
+
+ interface ExtensionAgeRestriction {
+ // The field ``critical`` is mandatory for an extension.
+ // Age restriction is not required to be understood by an client, so
+ // ``critical`` will be set to ``false``.
+ critical: false;
+
+ // The field ``version`` is mandatory for an extension. It is of type
+ // `LibtoolVersion`.
+ version: "1";
+
+ // Age restriction specific configuration
+ config: ConfigAgeRestriction;
+ }
+
+.. ts:def:: ConfigAgeRestriction
+
+ interface ConfigAgeRestriction {
+ // The age groups. This field is mandatory and binding in the sense
+ // that its value is taken into consideration when signing the
+ // age restricted denominations in the `ExchangeKeysResponse`
+ age_groups: AgeGroups;
+ }
+
+Age Groups
+~~~~~~~~~~
+
+Age groups are represented as a finite list of positive, increasing integers
+that mark the beginning of the *next* age group. The value 0 is omitted but
+implicitly marks the beginning of the *zeroth* age group and the first number
+in the list marks the beginning of the *first* age group. Age groups are
+encoded as a colon separated string of integer values. They are referred to by
+their *slot*, i.e. "age group 3" is the age group that starts with the 3.
+integer in the list.
+
+For example: the string "8:10:12:14:16:18:21" represents the age groups
+
+0. {0,1,2,3,4,5,6,7}
+#. {8,9}
+#. {10,11}
+#. {12,13}
+#. {14,15}
+#. {16,17}
+#. {18,19,20}
+#. {21, ⋯ }
+
+The field ``age_groups`` of type `AgeGroups` is mandatory and binding in the
+sense that its value is taken into consideration when signing the denominations
+in ``ExchangeKeysResponse.age_restricted_denoms``.
+
+.. ts:def:: AgeGroups
+
+ // Representation of the age groups as colon separated edges: Increasing
+ // from left to right, the values mark the beginning of an age group up
+ // to, but not including the next value. The initial age group starts at
+ // 0 and is not listed. Example: "8:10:12:14:16:18:21".
+ type AgeGroups = string;
+
+
+Age restricted denominations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If age-restriction is registered as extension ``age_restriction``, as described
+above, the root-object ``ExchangeKeysResponse`` in response to ``/keys`` MUST
+be extended by an additional field ``age_restricted_denoms``. This is an
+*additional* list of denominations that must be used during the modified
+``refresh`` and ``deposit`` operations (see below).
+
+The data structure for those denominations is the same as for the regular ones
+in ``ExchangeKeysResponse.denoms``. **However**, the following differences
+apply for each denomination in the list:
+
+1. The value of ``TALER_DenominationKeyValidityPS.denom_hash``
+ is taken over the public key of the denomination **and** the string in
+ ``ExtensionAgeRestriction.age_groups`` from the corresponding extension
+ object (see above).
+
+2. The value of ``TALER_DenominationKeyValidityPS.purpose`` is set to
+ ``TALER_SIGNATURE_MASTER_AGE_RESTRICTED_DENOMINATION_KEY_VALIDITY``.
+
+And similar to ``.denoms``, if the query parameter ``last_issue_date`` was
+provided by the client, the exchange will only return the keys that have
+changed since the given timestamp.
+
+
+.. ts:def:: ExchangeKeysResponse
+
+ interface ExchangeKeysResponse {
+ //...
+
+ // List of denominations that support age-restriction with the age groups
+ // given in age_groups. This is only set **iff** the extension
+ // ``age_restriction`` is registered under ``entensions`` with type
+ // ``ExtensionAgeRestriction``.
+ //
+ // The data structure for each denomination is the same as for the
+ // denominations in ExchangeKeysResponse.denoms. **However**, the
+ // following differences apply for each denomination in the list:
+ //
+ // 1. The value of ``TALER_DenominationKeyValidityPS.denom_hash``
+ // is taken over the public key of the denomination __and__ the
+ // string in ``ExtensionAgeRestriction.age_groups`` from the
+ // corresponding extension object.
+ //
+ // 2. The value of ``TALER_DenominationKeyValidityPS.purpose`` is set to
+ // ``TALER_SIGNATURE_MASTER_AGE_RESTRICTED_DENOMINATION_KEY_VALIDITY``
+ //
+ // Similar as for ``.denoms``, if the query parameter ``last_issue_date``
+ // was provided by the client, the exchange will only return the keys that
+ // have changed since the given timestamp.
+ age_restricted_denoms: DenomCommon[];
+
+ //...
+ }
+
+
+SQL schema
+-----------
+
+The exchange has to mark denominations with support for age restriction as such
+in the database. Also, during the melting phase of the refresh operation, the
+exchange will have to persist the SHA256 hash of the age commitment of the
+original coin.
+
+The schema for the exchange is changed as follows:
+
+.. sourcecode:: sql
+
+ -- Everything in one big transaction
+ BEGIN;
+ -- Check patch versioning is in place.
+ SELECT _v.register_patch('exchange-TBD', NULL, NULL);
+
+ -- Support for age restriction is marked per denomination.
+ ALTER TABLE denominations
+ ADD COLUMN age_restricted BOOLEAN NOT NULL DEFAULT (false);
+ COMMENT ON COLUMN denominations.age_restriced
+ IS 'true if this denomination can be used for age restriction';
+
+ -- During the melting phase of the refresh, the wallet has to present the
+ -- hash value of the age commitment (only for denominations with support
+ -- for age restriction).
+ ALTER TABLE refresh_commitments
+ ADD COLUMN age_commitment_h BYTEA CHECK (LENGTH(age_commitment_h)=64);
+ COMMENT ON COLUMN refresh_commitments.age_commitment_h
+ IS 'SHA256 hash of the age commitment of the old coin, iff the corresponding
+ denomimination has support for age restriction, NULL otherwise.';
+ COMMIT;
+
+Note the constraint on ``refresh_commitments.age_commitment_h``: It can be
+NULL, but only iff the corresponding denomination (indirectly referenced via
+table ``known_coins``) has ``.age_restricted`` set to true. This constraint
+can not be expressed reliably with SQL.
+
+
+Protocol changes
+----------------
+
+Withdraw
+~~~~~~~~
+
+The withdraw protocol is affected in the following situations:
+
+- A wire transfer to the exchange (to fill a reserve) was marked by the
+ originating bank as coming from a bank account of a minor, belonging to a of
+ a specific age group, or by other means.
+- A KYC-process has been performed with the owner of a reserve and the user has
+ been identified as being a minor.
+- A Peer-to-Peer transaction was performed between customers. The receiving
+ customer's KYC result tells the exchange that the customer belongs to a
+ specific age group.
+
+In these cases, the wallet will have to perform a zero-knowledge protocol with
+exchange as part of the the withdraw protocol, which we sketch here. Let
+
+- :math:`\kappa` be the same cut-and-choose parameter for the refresh-protocol.
+- :math:`\Omega \in E` be a published, nothing-up-my-sleeve, constant
+ group-element on the elliptic curve.
+- :math:`a \in \{1,\ldots,M\}` be the maximum age (group) for which the wallet
+ has to prove its commitment.
+
+The values :math:`\kappa`, :math:`\Omega` and :math:`a` are known to the
+Exchange and the Wallet. Then, Wallet and Exchange run the following protocol
+for the withdrawal of one coin:
+
+- *Wallet*
+ 1. creates planchets :math:`C_i` for :math:`i \in \{1,\ldots,\kappa\}` as candidates for *one* coin.
+ #. creates age-commitments :math:`\vec{Q}^i` for :math:`i \in \{1,\ldots,\kappa\}` as follows:
+
+ a) creates :math:`a`-many Edx25519-keypairs :math:`(p^i_j, q^i_j)`
+ randomly for :math:`j \in \{1,\ldots,a\}` (with public keys :math:`q^i_j`),
+ #) chooses randomly :math:`(M - a)`-many scalars :math:`s^i_j` for :math:`j \in \{a+1,\ldots,M\}`,
+ #) calculates :math:`\omega^i_j = s^i_j*\Omega` for :math:`j \in \{a+1,\ldots,M \}`,
+ #) sets :math:`\vec{Q}^i := (q^i_1,\ldots,q^i_a,\omega^i_{a+1},\ldots,\omega^i_M)`
+
+ #. calculates :math:`f_i := \text{FDH}(C_i, H(\vec{Q}^i))` for :math:`i \in \{ 1,\ldots,\kappa \}`.
+ #. chooses random blindings :math:`\beta_i(.)` for :math:`i \in \{1,\ldots,\kappa\}`. The blinding functions depend on the cipher (RSA, CS).
+ #. sends :math:`(\beta_1(f_1),\ldots,\beta_\kappa(f_\kappa))` to the Exchange
+
+- *Exchange*
+ 7. receives :math:`(b_1,\ldots,b_\kappa)`
+ #. calculates :math:`F := \text{H}(b_1||\ldots||b_\kappa)`
+ #. chooses randomly :math:`\gamma \in \{1,\ldots,\kappa\}` and
+ #. signs :math:`r := b_\gamma` resulting in signature :math:`\sigma_r`
+ #. stores :math:`F \mapsto (r, \sigma_r)`
+ #. sends :math:`\gamma` to the Wallet.
+
+- *Wallet*
+ 10. receives :math:`\gamma`
+ #. sends to the Exchange the tuple :math:`\left(F, \vec{\beta}, \vec{\vec{Q}}, \vec{\vec{S}}\right)` with
+
+ - :math:`F := \text{H}(\beta_1(f_1)||\ldots||\beta_\kappa(f_\kappa))`
+ - :math:`\vec{\beta} := (\beta_1,\ldots,\beta_{\gamma-1},\bot,\beta_{\gamma+1},\ldots,\beta_\kappa)`
+ - :math:`\vec{\vec{Q}} := (\vec{Q}^1,\ldots,\vec{Q}^{\gamma-1},\bot,\vec{Q}^{\gamma+1},\ldots,\vec{Q}^\kappa)`
+ - :math:`\vec{\vec{S}} := (\vec{S}^1,\ldots,\vec{S}^{\gamma-1},\bot,\vec{S}^{\gamma+1},\ldots,\vec{S}^\kappa)`
+ with :math:`\vec{S}^i := (s^i_j)`
+
+- *Exchange*
+ 12. receives :math:`\left(F, (\beta_i), (\vec{Q}^i), (\vec{B}^i) \right)`
+ #. retrieves :math:`(r, \sigma_r)` from :math:`F` or bails out if not present
+ #. calculates :math:`b_i := \beta_i\left(\text{FDH}(\vec{Q}^i)\right)` for :math:`i \neq \gamma`
+ #. compares :math:`F \overset{?}{=} \text{H}(b_1||\ldots||b_{\gamma - 1}||r||b_{\gamma+1}||\ldots||b_\kappa)` and bails out on inequality
+ #. for each :math:`\vec{B}^i, i \neq \gamma`
+
+ i. calculates :math:`\tilde{\omega}^i_j := b^i_j * \Omega` for :math:`j \in \{a+1,\ldots,M\}`
+ #. compares each :math:`\tilde{\omega}^i_j` to :math:`q^i_j` from :math:`\vec{Q}^i = (q^i_1, \ldots, q^i_M)` and bails out on inequality
+ #. sends (blinded) signature :math:`\sigma_r` to Wallet
+
+- *Wallet*
+ 18. receives :math:`\sigma_r`
+ #. calculates (unblinded) signature :math:`\sigma_\gamma := \beta^{-1}_\gamma(\sigma_r)` for coin :math:`C_\gamma`.
+
+
+Note that the batch version of withdraw allows the withdrawal of *multiple*
+coins at once. For that scenario the protocol sketched above is adapted to
+accomodate for handling multiple coins at once -- thus multiplying the amount
+of data by the amount of coins in question--, but all with the same value of
+:math:`\gamma`.
+
+The *actual* implementation of the protocol above will have major optimizations
+to keep the bandwidth usage to a minimum and also ensure that a denomination in
+the commitment doesn't expire before the reveal.
+
+Instead of generating and sending the age commitment (array of public keys) and
+blindings for each coin, the wallet *MUST* derive the corresponding blindings
+and the age commitments from the coin's private key itself as follows:
+
+Let
+
+- :math:`s` be the master secret of the coin, from which the private key :math:`c_s`, blinding :math:`\beta` and nonce :math:`n` are derived as usual in the wallet core
+- :math:`m \in \{1,\ldots,M\}` be the maximum age (according to the reserve)
+ that a wallet can commit to during the withdrawal.
+- :math:`P` be a published constant Edx25519-public-key to which the private
+ key is not known to any client.
+
+For the age commitment, calculate:
+
+1. For age group :math:`a \in \{1,\ldots,m\}`, set
+
+.. math::
+ s_a &:= \text{HDKF}(s, \text{"age-commitment"}, a) \\
+ p_a &:= \text{Edx25519\_generate\_private}(s_a) \\
+ q_a &:= \text{Edx25519\_public\_from\_private}(p_a)
+
+2. For age group :math:`a \in \{m,\ldots,M\}`, set
+
+.. math::
+ f_a &:= \text{HDKF}(s, \text{"age-factor"}, a) \\
+ q_a &:= \text{Edx25519\_derive\_public}(P, f_a).
+
+Then the vector :math:`\vec{q} = \{q_1,\ldots,q_M\}` is then the age commitment
+associated to the coin's private key :math:`c_s`. For the non-disclosed coins,
+the wallet can use the vector :math:`(p_1,\ldots,p_m,\bot,\ldots,\bot)` of
+private keys for the attestation.
+
+Provided with the secret :math:`s`, the exchange can therefore calculate the
+private key :math:`c_s`, the blinding :math:`\beta`, the nonce :math:`n` (if
+needed) and the age commitment :math:`\vec{q}`, along with the coin's public
+key :math:`C_p` and use the value of
+
+.. math::
+
+ \text{TALER\_CoinPubHashP}(C_p, \text{age\_commitment\_hash}(\vec{q}))
+
+during the verification of the original age-withdraw-commitment.
+
+For the withdrawal with age restriction, a sketch of the corresponding database
+schema in the exchange is given here:
+
+.. graphviz::
+
+ digraph deposit_policies {
+ rankdir = LR;
+ splines = true;
+ fontname="monospace"
+ node [
+ fontname="monospace"
+ shape=record
+ ]
+
+ subgraph cluster_commitments {
+ label=<<B>age_withdraw</B>>
+ margin=20
+ commitments [
+ label="age_withdraw_id\l|<hc>h_commitment\l|amount_with_fee_val\l|amount_with_fee_frac\l|noreveal_index\l|max_age\l|<res>reserve_pub\l|reserve_sig\l|<denom>[n] denominations_serials\l|[n] h_blind_evs\l|[n] denom_sigs\l"
+ ]
+ }
+
+ commitments:res->reserves:id [ label="n:1"; fontname="monospace"];
+ commitments:denom -> denominations:id [ label="n:1"; fontname="monospace"] ;
+ }
+
+
+Refresh - melting phase
+~~~~~~~~~~~~~~~~~~~~~~~
+
+During the melting phase of the refresh, the wallet has to present the hash
+value of the age commitment (for denominations with support for age
+restriction). Therefore, in the ``/coins/$COIN_PUB/melt`` POST request, the
+``MeltRequest`` object is extended with an optional field
+``age_commitment_hash``:
+
+.. ts:def:: MeltRequest
+
+ interface MeltRequest {
+ ...
+
+ // SHA256 hash of the age commitment of the coin, IFF the denomination
+ // has age restriction support. MUST be omitted otherwise.
+ age_commitment_hash?: AgeCommitmentHash;
+
+ ...
+ }
+
+.. ts:def:: AgeCommitmentHash
+
+ type AgeCommitmentHash = SHA256HashCode;
+
+The responses to the POST request remain the same.
+
+For normal denominations *without* support for age restriction, the calculation
+for the signature check is as before (borrowing notation from
+`Florian's thesis <https://taler.net/papers/thesis-dold-phd-2019.pdf>`_):
+
+.. math::
+ \text{FDH}_N(C_p)\; \stackrel{?}{=}\; \left(\sigma_C\right)^{e} \;\;\text{mod}\,N
+
+Here, :math:`C_p` is the EdDSA public key of a coin, :math:`\sigma_C` is its
+signature and :math:`\langle e, N \rangle` is the RSA public key of the
+denomination.
+
+For denominations *with* support for age restriction, the exchange takes the
+hash value ``age_commitment_hash`` (abbreviated as :math:`h_a`) into account
+when verifying the coin's signature:
+
+.. math::
+ \text{FDH}_N(C_p, h_a)\; \stackrel{?}{=}\; \left(\sigma_C\right)^{e} \;\;\text{mod}N
+
+
+
+
+Refresh - reveal phase
+~~~~~~~~~~~~~~~~~~~~~~
+
+During the reveal phase -- that is upon POST to ``/refreshes/$RCH/reveal`` --
+the client has to provide the original age commitment of the old coin (i.e. the
+vector of public keys), iff the corresponding denomination had support for age
+restriction. The size of the vector is defined by the Exchange implicetly as
+the amount of age groups defined in the field ``.age_groups`` of the
+``ExtensionAgeRestriction``.
+
+.. ts:def:: RevealRequest
+
+ interface RevealRequest {
+ ...
+
+ // Iff the corresponding denomination has support for age restriction,
+ // the client MUST provide the original age commitment, i.e. the vector
+ // of public keys.
+ // The size of the vector is defined by the Exchange implicetly as the
+ // amount of age groups defined in the field ``.age_groups`` of the
+ // ``ExtensionAgeRestriction``.
+ old_age_commitment?: Edx25519PublicKey[];
+
+
+ ...
+ }
+
+
+The exchange can now check if the provided public keys ``.old_age_commitment``
+have the same SHA256 hash value when hashed in sequence as the
+``age_commitment_hash`` of the original coin from the call to melt.
+
+The existing `cut&choose protocol during the reveal phase
+</core/api-exchange.html#post--refreshes-$RCH-reveal>`__ is extended to perform
+the following additional computation and checks:
+
+Using the κ-1 transfer secrets :math:`\tau_i` from the reveal request, the
+exchange derives κ-1 age commitments from the ``old_age_commitment`` by calling
+``Edx25519_derive_public()`` on each `Edx25519PublicKey`, with :math:`\tau_i`
+as the seed, and then calculates the corresponding κ-1 hash values :math:`h_i`
+of those age commitments.
+
+It then calculates the κ-1 blinded hashes
+:math:`m_i = r^{e_i}\text{FDH}_N(C^{(i)}_p, h_i)` (using the notation from Florian's
+thesis) of the disclosed coins and together with the :math:`m_\gamma` of the
+undisclosed coin, calculates the hash
+:math:`h'_m = H(m_1,\cdots,m_\gamma,\cdots,m_\kappa)` which is then used in the
+final verification step of the cut&choose protocol.
+
+
+Deposit
+~~~~~~~
+
+As always, the merchant has to provide the public key of a coin during a POST
+to ``/coins/$COIN_PUB/deposit``. However, for coins with age restriction, the
+signature check requires the hash of the age commitment. Therefore the request
+object ``DepositRequest`` is extended by an optional field
+``age_commitment_hash`` which MUST be set (with the SHA256 hash of the age
+commitment), iff the corresponding denomination had support for age restriction
+enabled. The merchant has received this value prior from the customer during
+purchase.
+
+.. ts:def:: DepositRequest
+
+ interface DepositRequest {
+ ...
+
+ // Iff the corresponding denomination had support for age restriction
+ // enabled, this field MUST contain the SHA256 value of the age commitment that
+ // was provided during the purchase.
+ age_commitment_hash?: AgeCommitmentHash;
+
+ ...
+ }
+
+Again, the exchange can now check the validity of the coin with age restriction
+by evaluating
+
+.. math::
+ \text{FDH}_N(C_p, h_a)\; \stackrel{?}{=}\; \left(\sigma_C\right)^{e} \;\;\text{mod}N
+
+Also again, :math:`C_p` is the EdDSA public key of a coin, :math:`\sigma_C` is
+its signature, :math:`\langle e, N \rangle` is the RSA public key of the
+denomination and :math:`h_a` is the value from ``age_commitment_hash``.
+
+
+
+Changes in the Merchant API
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+
+Claiming the order
+------------------
+
+If an order requires a minimum age, the merchant MUST express that required
+minimum age in response to order claim by the wallet, that is, a POST to
+``[/instances/$INSTANCE]/orders/$ORDER_ID/claim``.
+
+The object ``ContractTerms`` is extended by an optional field
+``minimum_age`` that can be any integer greater than 0. In reality
+this value will not be smaller than, say, 8, and not larger than, say, 21.
+
+.. ts:def:: DD24ContractTerms
+
+ interface DD24ContractTerms {
+ ...
+
+ // If the order requires a minimum age greater than 0, this field is set
+ // to the integer value of that age. In reality this value will not be
+ // smaller than, say, 8, and not larger than, say, 21.
+ minimum_age?: Integer;
+
+ ...
+ }
+
+By sending the contract term with the field ``minimum_age`` set to an
+non-zero integer value, the merchant implicetly signals that it understands the
+extension ``age_restriction`` for age restriction from the exchange.
+
+
+Making the payment
+------------------
+
+If the ``ContractTerms`` had a non-zero value in field
+``minimum_age``, the wallet has to provide evidence of that minimum
+age by
+
+#. *either* using coins which are of denominations that had *no* age support
+ enabled,
+
+#. *or* using coins which are of denominations that have support for age
+ restriction enabled
+
+ * and then ―for each such coin― it has the right private key of the
+ restricted age commitment to the age group into which the required minimum
+ age falls (i.e. a non-empty entry at the right index in vector of Edx25519
+ keys, see above).
+
+ * and signs the required minimum age with each coin's private key
+ corresponding to the age group,
+
+ * and sends ―for each coin― the complete age commitment and the signature to
+ the merchant.
+
+The object ``CoinPaySig`` used within a ``PayRequest`` during a POST to
+``[/instances/$INSTANCE]/orders/$ORDER_ID/pay`` is extended as follows:
+
+.. ts:def:: CoinPaySig
+
+ export interface CoinPaySig {
+ ...
+
+ // If a minimum age was required by the order and the wallet had coins that
+ // are at least committed to the corresponding age group, this is the
+ // signature of the minimum age as a string, using the private key to the
+ // corresponding age group.
+ minimum_age_sig?: Edx25519Signature;
+
+ // If a minimum age was required by the order, this is age commitment bound
+ // to the coin, i.e. the complete vector of Edx25519_ public keys, one for each
+ // age group (as defined by the exchange).
+ age_commitment?: Edx25519PublicKey[];
+
+ }
+
+
+The merchant can now verify
+
+#. the validity of each (age restricted) coin by evaluating
+
+ .. math:: \text{FDH}_N(C_p, h_a)\; \stackrel{?}{=}\; \left(\sigma_C\right)^{e} \;\;\text{mod}N
+
+ Again, :math:`C_p` is the EdDSA public key of a coin, :math:`\sigma_C` is
+ its signature, :math:`\langle e, N \rangle` is the RSA public key of the
+ denomination and :math:`h_a` is the SHA256 hash value of the vector in
+ ``age_commitment``.
+
+#. the minimum age requirement by checking the signature in ``minimum_age_sig``
+ against the public key ``age_commitment[k]`` of the corresponding age group,
+ say, ``k``. (The minimum age must fall into the age group at index ``k`` as
+ defined by the exchange).
+
+**Note**: This applies only to coins for denominations that have support for
+age restriction. Denominations *without* support for age restriction *always*
+satisfy any minimum age requirement.
+
+
+
+Changes in the Wallet
+^^^^^^^^^^^^^^^^^^^^^
+
+A wallet implementation SHOULD support denominations with age restriction. In
+that case it SHOULD allow to select an age group as upper bound during
+withdraw.
+
+
+Alternatives
+============
+
+* ID-based systems
+* credit/debit card based systems
+
+
+Drawbacks
+=========
+
+* age groups, once defined, are set permanently
+
+Also discuss:
+
+* storage overhead
+* computational overhead
+* bandwidth overhead
+* legal issues?
+
+Discussion / Q&A
+================
+
+We had some very engaged discussions on the GNU Taler `mailing list <taler@gnu.org>`__:
+
+* `Money with capabilities <https://lists.gnu.org/archive/html/taler/2021-08/msg00005.html>`_
+
+* `On age-restriction (was: online games in China) <https://lists.gnu.org/archive/html/taler/2021-09/msg00006.html>`__
+
+* `Age-restriction is about coins, not currencies <https://lists.gnu.org/archive/html/taler/2021-09/msg00021.html>`__
+
+* The published paper: `Zero Knowledge Age Restriction for GNU Taler <https://link.springer.com/chapter/10.1007/978-3-031-17140-6_6>`_
+
+
+.. _Edx25519:
+
+Edx25519
+========
+
+Edx25519 is a variant of EdDSA on curve25519 which allows for repeated
+derivation of private and public keys, independently. It is implemented in
+`GNUNET with commit ce38d1f6c9bd7857a1c3bc2094a0ee9752b86c32.
+<https://git.gnunet.org/gnunet.git/commit/?id=ce38d1f6c9bd7857a1c3bc2094a0ee9752b86c32>`__
+
+The private keys in Edx25519 initially correspond to the data after expansion
+and clamping in EdDSA. However, this correspondence is lost after deriving
+further keys from existing ones. The public keys and signature verification
+are compatible with EdDSA.
+
+The scheme is as follows:
+
+::
+
+ /* Private keys in Edx25519 are pairs (a, b) of 32 byte each.
+ * Initially they correspond to the result of the expansion
+ * and clamping in EdDSA.
+ */
+
+ Edx25519_generate_private(seed) {
+ /* EdDSA expand and clamp */
+ dh := SHA-512(seed)
+ a := dh[0..31]
+ b := dh[32..64]
+ a[0] &= 0b11111000
+ a[31] &= 0b01111111
+ a[31] |= 0b01000000
+
+ return (a, b)
+ }
+
+ Edx25519_public_from_private(private) {
+ /* Public keys are the same as in EdDSA */
+ (a, _) := private
+ return [a] * G
+ }
+
+ Edx25519_blinding_factor(P, seed) {
+ /* This is a helper function used in the derivation of
+ * private/public keys from existing ones. */
+ h1 := HKDF_32(P, seed)
+
+ /* Ensure that h == h % L */
+ h := h1 % L
+
+ /* Optionally: Make sure that we don't create weak keys. */
+ P' := [h] * P
+ if !( (h!=1) && (h!=0) && (P'!=E) ) {
+ return Edx25519_blinding_factor(P, seed+1)
+ }
+
+ return h
+ }
+
+ Edx25519_derive_private(private, seed) {
+ /* This is based on the definition in
+ * GNUNET_CRYPTO_eddsa_private_key_derive. But it accepts
+ * and returns a private pair (a, b) and allows for iteration.
+ */
+ (a, b) := private
+ P := Edx25519_public_key_from_private(private)
+ h := Edx25519_blinding_factor(P, seed)
+
+ /* Carefully calculate the new value for a */
+ a1 := a / 8;
+ a2 := (h * a1) % L
+ a' := (a2 * 8) % L
+
+ /* Update b as well, binding it to h.
+ This is an additional step compared to GNS. */
+ b' := SHA256(b ∥ h)
+
+ return (a', b')
+ }
+
+ Edx25519_derive_public(P, seed) {
+ h := Edx25519_blinding_factor(P, seed)
+ return [h]*P
+ }
+
+ Edx25519_sign(private, message) {
+ /* As in Ed25519, except for the origin of b */
+ (d, b) := private
+ P := Edx25519_public_from_private(private)
+ r := SHA-512(b ∥ message)
+ R := [r] * G
+ s := r + SHA-512(R ∥ P ∥ message) * d % L
+
+ return (R,s)
+ }
+
+ Edx25519_verify(P, message, signature) {
+ /* Identical to Ed25519 */
+ (R, s) := signature
+ return [s] * G == R + [SHA-512(R ∥ P ∥ message)] * P
+ }
diff --git a/design-documents/025-withdraw-from-wallet.rst b/design-documents/025-withdraw-from-wallet.rst
new file mode 100644
index 00000000..d37fc04b
--- /dev/null
+++ b/design-documents/025-withdraw-from-wallet.rst
@@ -0,0 +1,66 @@
+DD 25: Withdraw coins manually starting from the wallet
+#######################################################
+
+Summary
+=======
+
+This document presents the design discussion about the manual withdraw screens
+
+Motivation
+==========
+
+To have a way to initiate a withdrawal process and complete with a bank that is
+not aware of GNU Taler
+
+Proposed Solution
+=================
+
+Access to the feature
+^^^^^^^^^^^^^^^^^^^^^
+
+Adding a withdraw button in the main balance page to initiate the process.
+
+This feature can be use in the Pay call-to-action when there is not enough coins.
+
+Start
+^^^^^
+
+This screen the user will be able to select the currency from a list of known
+currencies, switch the exchange, go to a page to add an exchange and define an
+amount to be withdraw.
+
+.. image:: ../images/wallet-start-manual-withdraw.svg
+ :width: 800
+
+
+Success
+^^^^^^^
+
+Here the user will see the account details where it needs to send money to
+complete the withdrawal.
+
+.. image:: ../images/wallet-confirm-withdraw.svg
+ :width: 800
+
+Transaction history
+^^^^^^^^^^^^^^^^^^^
+
+The account information should be added into the Withdrawal Transaction detail
+screen if the withdrawal is still pending. This will also affect the use case
+when the user started the transaction from a taler-aware bank (in which case the
+user doesn't need to do an extra step to complete the process) so the text
+should be consistent in both scenarios.
+
+Alternatives
+============
+
+* removing the amount field, the exchange will send coins equal to the amount it received
+
+* showing the fees, can we calculate the withdrawal fee?
+
+* should we show the terms of service?
+
+* exchange field first has been discussed, but the exchange list its only showing the
+ current currency exchanges, the user need to switch the currency first. Adding a
+ new exchange should be done in a different context that can be accessed using the
+ ``add exchange`` link
diff --git a/design-documents/026-refund-fees.rst b/design-documents/026-refund-fees.rst
new file mode 100644
index 00000000..b2d03066
--- /dev/null
+++ b/design-documents/026-refund-fees.rst
@@ -0,0 +1,65 @@
+DD 26: Refunds and Fees
+#######################
+
+.. note::
+
+ This is implemented (as of 2023-09-15).
+
+Summary
+=======
+
+This document discusses what should happen with deposit fees when a
+deposit is refunded.
+
+
+Motivation
+==========
+
+When a user receives a refund, we have to decide what happens to the deposit
+fee that was originally paid on the associated deposit. Originally, we said
+that the deposit fee is waived when any refund happens. However, if the
+refund fee is zero and the deposit fee is non-zero, this results in a
+problematic scenario where merchants issue minuscule refunds that primarily
+enable customers to effectively obtain the deposit fee.
+
+
+Requirements
+============
+
+ * If the refund and refresh fees are zero, it should be possible for
+ consumers to get 100% of their digital cash back on refunds.
+ * This should not result in a problematic situation where merchants
+ conspire with consumers and issue minuscule refunds to allow consumers
+ to work around deposit fees.
+
+Proposed Solution
+=================
+
+ * Only waive the deposit fee for full refunds where for the
+ specific coin (!) the refunded amount is the total value of the
+ refunded deposit.
+
+Alternatives
+============
+
+ * Only waive the deposit fee for full refunds where for the
+ specific coin the refunded amount is the total value of the
+ denomination of the coin. This may slightly simplify the
+ logic, but has the problem that it does not enable 100%
+ refunds if the original payment already required a refresh
+ because the coin's value exceeded the paid amount.
+ * Waive the deposit fee on any (including partial) refund.
+ This creates a bad incentive structure if combined refresh
+ and refund fees are below deposit fees.
+
+Drawbacks
+=========
+
+ * We need to update and test an already complex fee calculation
+ logic.
+
+
+Discussion / Q&A
+================
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/027-sandboxing-taler.rst b/design-documents/027-sandboxing-taler.rst
new file mode 100644
index 00000000..1a09baf4
--- /dev/null
+++ b/design-documents/027-sandboxing-taler.rst
@@ -0,0 +1,165 @@
+DD 27: Sandboxing all the Taler services
+########################################
+
+.. note::
+
+ This design document is currently a draft, it
+ does not reflect any implementation decisions yet.
+
+Summary
+=======
+
+This document presents a method of deploying all the Taler
+services via one Docker container.
+
+Motivation
+==========
+
+It is very difficult to build GNU Taler from scratch. It is even more difficult
+to install, configure and launch it correctly.
+
+The purpose of the sandbox is to have a demonstration system that can be both
+build and launched with ideally a single command.
+
+Requirements
+============
+
+- No external services should be required, the only dependencies should be:
+
+ - podman/docker
+ - optionally: configuration files to further customize the setup
+
+- All services that are used should be installed from repositories
+ and not built from scratch (i.e. debian repos or PyPI)
+
+- There should be some "admin page" for the whole sandbox that:
+
+ - Show an overview of all deployed services, a link to their documentation
+ and the endpoints they expose
+ - Show very simple statistics (e.g. number of transactions / withdrawals)
+ - Allows generating and downloading the auditor report
+
+- Developers should be able to launch the sandbox on their own machine
+
+ - Possibly using nightly repos instead of the official stable repos
+
+- We should be able to deploy it on $NAME.sandbox.taler.net
+
+Design
+======
+
+The container is based on Debian Sid, and it installs all
+the services from their Debian packages. During the build
+process, it creates all the 'static' configuration. This
+one includes all the .conf-files, the database setup and the
+keying.
+
+Subsequently at the launch step, the system will create all
+the remaining RESTful resources. Such RESTful resources include
+the merchant instances and all the euFin accounts, both at Sandbox
+and at Nexus.
+
+The sandbox will serve one HTTP base URL and make any service
+reachable at $baseUrl/$service. For example, the exchange base
+URL will be "$baseUrl/exchange".
+
+The sandbox allows to configure:
+
+- which host it binds to, typically localhost+port.
+- which host is being reverse proxied to the sandbox. This
+ helps to generate valid URIs of services.
+
+All the other values will be hard-coded in the preparation.
+
+The database is aunched *in* the same container along the
+other services.
+
+Open questions
+==============
+
+- How to collect the static configuration values?
+
+ - => Via a configuration file that you pass to the container via
+ a mounted directory (=> ``-v $MYCONFIG:/sandboxconfig``)
+ - If we don't pass any config, the container should have
+ sane defaults
+ - This is effectively a "meta configuration", because it will
+ be used to generate the actual configuration files
+ and do RESTful configuration at launch time.
+
+- How to persist, at build time, the information
+ needed later at launch time to create the RESTful
+ resources?
+
+ - => The configuration should be done at launch-time of the container.
+
+- Should we at this iteration hard-code passwords too?
+ With generated passwords, (1) it won't be possible to
+ manually log-in to services, (2) it won't be possible
+ to write the exchange password for Nexus in the conf.
+ Clearly, that's a problem when the sandbox is served
+ to the outside.
+
+- How is data persisted? (i.e. where do we store stuff)
+
+ - By allowing to mount some data directory on the host of the container
+ (This stores the DB files, config files, key files, etc.)
+ - ... even for data like the postgresql database
+ - future/optional: we *might* allow connection to an external postgresql database as well
+
+- How are services supervised?
+
+ - SystemD? gnunet-arm? supervisord? something else?
+
+ - SystemD does not work well inside containers
+
+ - alternative: one container per service, use (docker/podman)-compose
+
+ - Either one docker file per service, *or* one base container that
+ can be launched as different services via command line arg
+
+ - Advantage: It's easy to see the whole architecture from the compose yaml file
+ - Advantage: It would be easy to later deploy this on kubernetes etc.
+
+ - list of containers:
+
+ - DB container (postgres)
+ - Exchange container (contains all exchange services, for now)
+ - Split this up further?
+ - Merchant container
+
+- Do we have multi-tenancy for the sandbox? (I.e. do we allow multiple
+ currencies/exchanges/merchants/auditors per sandbox)
+
+ - Might be simpler if we disallow this
+
+- How do we handle TLS
+
+ - Do we always do HTTPs in the sandbox container?
+ - We need to think about external and internal requests
+ to the sandbox
+
+- How do we handle (external vs internal) URLs
+
+ - If we use http://localhost:$PORT for everything, we can't expose
+ the services externally
+ - Example 1: Sandbox should run on sb1.sandbox.taler.net.
+
+ - What will be the base URL for the exchange in the merchant config?
+ - If it's https://sb1.sandbox.taler.net/exchange, we need some /etc/hosts entry
+ inside the container
+ - Once you want to expose the sandbox internally, you need a proper TLS cert (i.e. letsencrypt)
+ - Inside the container, you can get away with self-signed certificates
+ - Other solution: Just require the external nginx (e.g. at gv) to reverse proxy
+ sb1.sandbox.taler.net back to the container. This means that all communication
+ between services inside the sandbox container goes through gv
+
+ - Not great, but probably fine for first iteration
+ - Disadvantages: To test the container in the non-localhost mode, you need the external proxy running
+
+- Where do we take packages from?
+
+ - By default, from the stable taler-systems.com repos and PyPI
+ - Alternatively, via the nightly gv debian repo
+ - Since we install packages at container build time, this setting (stable vs nightly)
+ results in different container base images
diff --git a/design-documents/028-deposit-policies.rst b/design-documents/028-deposit-policies.rst
new file mode 100644
index 00000000..1bdf4801
--- /dev/null
+++ b/design-documents/028-deposit-policies.rst
@@ -0,0 +1,207 @@
+DD 28: Deposit Policy Extensions
+################################
+
+.. note::
+
+ This is Work-In-Progress.
+
+Summary
+*******
+
+We will propose here a plugable mechanism in the exchange to support deposits
+with associated policy. An exchange can enable support for such policies via
+configuration.
+
+The inital set of policy extensions that an exchange might provide consists of
+
+Merchant refunds
+ Merchant can grant customers refundable payments. In this case, the
+ amount of the deposit is put into escrow by the exchange for a certain
+ period until which the customer can claim a refund.
+
+Escrowed payments
+ A trustor puts coins into escrow with the exchange. It can be claimed
+ by a beneficiary until a certain deadline, when the claim is signed by
+ both, the beneficiary's and the trustor's keys.
+
+Brandt-Vickrey auctions
+ A bidder puts coins into escrow with the exhange in order to
+ participate in an Brandt-Vickrey auction. The deposit confirmation is
+ proof to the seller for the escrow and contains a hash of the auction
+ meta-data and a deadline. After successfull execution of the auction,
+ the seller provides a valid transcript to the exchange from which the
+ exchange learns which bidder(s) won the auction for which prices. It
+ then transfers the amounts from the winners' coins to the seller. In
+ case of a timeout and for all losing bidders, the coins can be
+ refreshed.
+
+The policies shall be implemented as *extensions* to the exchange (see
+:doc:`006-extensions`).
+
+Motivation
+**********
+
+GNU Taler's initial set of API's (withdraw, deposit, refresh) support most
+payment situations in which customers pay for goods and services within an
+otherwise unconditioned transaction. (A notable exception from this the
+ability to provide refunds, which will be re-factored into a policy extension).
+
+However, in many payments depend on additional conditions to be met. GNU Taler
+already supports payments with age restriction applied, but there are other
+scenarious that we want to support.
+
+Our aim is to provide an API for extensions of GNU Taler that implement
+particular policies and policy-handling for payments (also called *conditioned
+payments*).
+
+
+Background and Requirements
+***************************
+
+TODO
+
+Proposed Solution
+*****************
+
+TODO, explain:
+
+- C-structs for policy extensions (esp. the handlers)
+- Naming conventions for policy extensions
+- Deadlines and -handling
+- Typical choreography of a deposit with policy and its fulfillment
+
+
+API-Endpoints of the Exchange
+=============================
+
+TODO
+
+
+
+Database-schema
+===============
+
+TODO: Description
+
+.. graphviz::
+
+ digraph deposit_policies {
+ rankdir = LR;
+ splines = false;
+ fontname="monospace"
+ node [
+ fontname="monospace"
+ shape=record
+ ]
+
+ subgraph cluster_deposits {
+ label=<<B>deposits</B>>
+ margin=20
+ deposits [
+ label="...|<ref>policy_details_id (null)\l|...|timestamp\l|..."
+ ]
+ }
+
+ subgraph cluster_policy_details {
+ label=<<B>policy_details</B>>
+ margin=20
+ policy_details [
+ label="<id>id\l|<hash>policy_hash_code (unique)\l|deadline\l|commitment (amount)\l|accumulated_total (amount)\l|fee (amount)\l|transferable (amount)\l|fulfillment_state\l|<fid>fulfillment_id (null)\l"
+ ]
+ }
+
+ subgraph cluster_policy_fulfillments {
+ label=<<B>policy_fulfillments</B>>
+ margin=20
+ rank=min;
+ policy_fulfillments [
+ label="<id>id\l|proof\l|timestamp\l|<codes>policy_hash_codes (blob)\l"
+ ]
+ }
+
+ deposits:ref->policy_details:id [ label="n:1"; fontname="monospace" ];
+ policy_details:fid->policy_fulfillments:id [label="n:1"; fontname="monospace" ];
+ }
+
+
+The field ``policy_hash_codes`` in table ``policy_fulfillments`` is a binary
+blob that consists of the concatenation of the sorted
+``policy_details.policy_hash_code`` entries from all policies that are fulfilled by
+this proof.
+
+
+Policy Fulfillment States
+=========================
+
+The fulfillment of a policy can be in one of the following five states:
+
+Ready
+ The policy is funded and ready. The exchange is waiting for a proof of
+ fulfillment to arrive before the deadline.
+
+Insufficient
+ The policy lacks funding, that is ``accumulated_total`` <
+ ``commitment``, but has otherwise been accepted. Funding can be
+ continued by calling ``/deposit`` or ``/batch-deposit`` with more coins
+ and the same policy details.
+
+Success
+ The policy is provably fulfilled. The amounts for payout, fees and
+ refresh are transfered/can be claimed. Note that a policy fulfillment
+ handler can change the values for the amounts for payout, fees and
+ refresh.
+
+Timeout
+ The policy has timed out. The amounts for payout and refresh are
+ transfered/can be claimed.
+
+Failure
+ The policy is in an failure state. Payouts and refreshes are
+ blocked, timeouts are ignored.
+
+
+
+Invariants
+^^^^^^^^^^
+
+The following invariants need to be fulfilled and be checked by the auditor:
+
+- The fulfillment state of a policy is **Insufficient** IF AND ONLY IF the
+ amount in ``policy_details.commitment`` is equal or larger than the amount in
+ ``policy_details.accumulated_total``.
+
+- The sum of amounts in ``policy_details.fee`` and
+ ``policy_details.transferable`` MUST be equal or less than the amount in
+ ``policy_details.accumulated_total``.
+
+- The amount in ``policy_details.accumulated_total`` MUST be equal to the total
+ sum of contributions of the individual coins of the deposits that reference
+ this policy.
+
+- Each hash code encoded in ``policy_fulfillments.policy_hash_codes`` MUST
+ refer to an existing ``policy_details.hash_code`` AND its ``.fulfillment_id``
+ MUST point to the same ``policy_fulfillments.id``.
+
+- Conversely: If a ``policy_details.fulfillment_id`` points to an entry in
+ ``policy_fulfillment``, the ``policy_details.policy_hash_code`` MUST be
+ present in that entry's ``.policy_hash_codes``.
+
+
+
+Alternatives
+============
+
+TODO
+
+Drawbacks
+=========
+
+TODO
+
+
+Discussion / Q&A
+================
+
+TODO
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/029-mobile-ui.rst b/design-documents/029-mobile-ui.rst
new file mode 100644
index 00000000..fef5ae08
--- /dev/null
+++ b/design-documents/029-mobile-ui.rst
@@ -0,0 +1,41 @@
+DD 29: Mobile P2P UI
+####################
+
+Summary
+=======
+
+Design the ui and interaction of p2p payments using mobile
+
+Motivation
+==========
+
+The wallet user should be able to easily send and receive money to and from other wallet.
+
+Requirements
+============
+
+ * It should work even if the user does not have other communication channel
+ * Use the swipe up (to send) and swipe down (to request) gesture as other apps do
+ * It should be able to request payment before any withdraw (currency still unknown)
+ * It should support multi-device
+ * The user may opt-in to be findable through a registry service
+
+Proposed Solution
+=================
+
+.. image:: ../images/wallet-mobile-overview.svg
+ :width: 800
+
+
+Alternatives
+============
+
+Drawbacks
+=========
+
+
+
+Discussion / Q&A
+================
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/030-offline-payments.rst b/design-documents/030-offline-payments.rst
new file mode 100644
index 00000000..d4b4bae5
--- /dev/null
+++ b/design-documents/030-offline-payments.rst
@@ -0,0 +1,99 @@
+DD 30: Offline payments
+#######################
+
+Summary
+=======
+
+This design document discusses support for offline payments.
+
+Motivation
+==========
+
+Many proposed CBDCs claim to support offline payments.
+Taler is explicitly meant to be an online payment system. However, since there
+recently seems to be an increased interest in offline CBDC solutions,
+we have decided to still explore how Taler could support offline payments in the future.
+
+While we still recommend online-only payments, this work operates under the the
+following theme: "If Taler can support offline payments that are no worse than
+those of competing systems (that often offer less freedom and privacy to
+users), why should we claim we can't support them and fare worse in comparisons"?
+
+Requirements
+============
+
+TBD.
+
+Possible Solutions
+==================
+
+Approach 1: Trust-based offline payments
+----------------------------------------
+
+The merchant simply trusts payments without depositing them at the exchange, up
+to a certain threshold and when an emergency mode is activated.
+
+Advantages:
+
+- Offers the most user freedom
+- Very few protocol/implementation changes required
+
+Disadvantages:
+
+- Requires manual switching to "emergency mode" where merchant
+ just trusts payments without verification.
+- Linkability of transactions unavoidable, because refresh is not available offline
+- Unclear if/how business logic based on order state will be affected.
+ (Will there be a "paid-offline" / "paid-unconfirmed" state for orders?)
+
+Approach 2: Full HSM wallet
+---------------------------
+
+Implement the full wallet in a hardware security module. When paying, the HSM
+wallet attests itself to the merchant, who then (if configured appropriately)
+trusts that the coins are still valid without talking to the exchange first.
+
+Advantages:
+
+- Easy to lift coins out of the HSM into a software wallet.
+ The HSM would internally mark the coins as "online" and give
+ the coin secrets to the software wallet.
+- Few exchange/merchant protocol changes required.
+
+Disadvantages:
+
+- Complex implementation, might not be supported on commodity HSMs.
+- Requires medium-to-major merchant backend changes (to verify HSM sigs and
+ deposit coins once offline)
+- Difficult to support P2P payments
+- Depending on available coins, linkable transactions
+ might be unavoidable.
+- Since the HSM wallet supports the full protocol, regulators might
+ be encouraged to make the HSM a requirement for *all* payments.
+- The usual (justified!) HSM security and freedom concerns
+
+Approach 3: Light-weight HSM balance register
+---------------------------------------------
+
+The HSM maintains an offline balance, effectively as a single, HSM protected
+register. To obtain offline cash, the software wallet spends coins to get a
+signature that can be passed to the HSM to increment the offline balance.
+To spend, the software wallet requests an "offline deposit permission"
+that decrements the HSM balance register. The exchange accepts these offline
+deposit permissions in lieu of a normal coin deposit permission.
+
+Advantages:
+
+- Trivially supports P2P payments
+- Cleanly separates normal Taler functionality from offline functionality
+
+Disadvantages:
+
+- Requires non-trivial (but backwards compatible) protocol changes
+- The usual (justified!) HSM security and freedom concerns
+
+
+Discussion / Q&A
+================
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/031-invoicing.rst b/design-documents/031-invoicing.rst
new file mode 100644
index 00000000..0fcc88fd
--- /dev/null
+++ b/design-documents/031-invoicing.rst
@@ -0,0 +1,195 @@
+DD 31: Invoicing
+################
+
+Summary
+=======
+
+This document proposes new endpoints to support invoicing.
+
+
+Motivation
+==========
+
+We want to support a limited number of PULL payment requests where a purse is
+created for a reserve without immediately requiring a purse fee. However, we
+must prevent users from excessively creating purses (and uploading contracts)
+as we do not want the exchange to be abused as a storage layer. Furthermore,
+it would be good if the user sending a PULL payment request was properly
+identified to the payer.
+
+This design addresses bugs #7269 and #7274.
+
+
+Requirements
+============
+
+ * Effectively limit the number of open purses created by each individual
+ (or require purse fees if limit is exceeded).
+
+ * Ensure user has done KYC before doing a merge.
+ (Assuming the exchange does KYC at all.)
+
+ * Use information from KYC process to help payer identify payee.
+
+ * Reasonable UX and overall design impact.
+
+ * Wallets may want to pay for the reserve with coins
+ (reserve fresh, not created via bank transfer).
+
+Unclear in the current proposal are:
+
+ * Here (and in other places!), the payment of the KYC
+ fee remains, eh, obscure. This should probably be
+ part of the KYC endpoints, and not for each
+ KYC-trigger.
+
+ * Proposed table structure does not properly capture
+ if user paid extra for more purses (I could open
+ for 3 years, then pay for 5x purses in year 1, but
+ should not automatically get 5x purses in years 2/3).
+
+
+Proposed Solution
+=================
+
+Allow users to tie their identity to a reserve "on demand" and when doing so
+charge the ``account_fee``, bump the number of open purses threshold in the
+``reserves`` table and stop auto-closing of the reserve. This will ensure that
+the users can withdraw the reserve balance into their wallet even after a
+longer time period. This helps if the invoice is paid after a significant
+delay. Introduce a way to force an immediate closure of a reserve, allowing
+P2P reserve from invoices to be send to a bank account (this allows a wallet
+to be used for convenient invoicing and not strictly require the wallet to
+receive the funds).
+
+The solution needs three new tables for:
+
+ * account creation data:
+
+ - serial
+ - timestamp
+ - signature affirming desire to create account
+ - KYC requirement row
+
+ * account creation payment data:
+
+ - serial (for replication)
+ - coin signature (affirming payment)
+ - amount contributed
+ - account creation link (serial row ID)
+
+ * reserve closure request data:
+
+ - serial (for replication)
+ - timestamp
+ - reserve signature
+ - target account payto:// URI
+
+
+Specifically, the solution involves three new endpoints:
+
+Opening reserves
+----------------
+
+ * This new endpoint ``/reserve/$RID/open`` allows the user to
+ pay (for a year) to create a fixed number of purses and
+ to keep the reserve ``open`` (preventing auto-close); the
+ endpoint typically triggers a first (balance-independent)
+ KYC process (451) for a new KYC operation ``invoicing``
+ (unless KYC is off).
+
+ * Upon completion of the ``invoicing`` KYC, the wallet
+ must again try to ``/open``. If successful, the wallet
+ may be asked to pay the annual fee (402). However,
+ usually the wallet should be aware of the fee, and already
+ have included a suitable deposit in the POST to the endpoint.
+
+ * Once the annual fee is paid, the now open
+ reserve is set to a non-zero counter of allowed concurrently
+ open purses, and the expiration time of the reserve is bumped
+ to the end of the time period for which the fee was paid.
+
+Reserve Attestation
+-------------------
+
+ * This new endpoint ``/reserve/$RID/attest`` allows the user to
+ obtain exchange-signed KYC information about themselves.
+ This will basically be a list of (GANA standardized) attributes
+ and exchange signatures. The user can then choose which of
+ these attributes to include when invoicing. The available
+ set of attributes may differ depending on the KYC providers
+ configured and the attributes returned by the KYC logic.
+ We may choose to not use any fancy cryptography here, and
+ simply sign the different attributes individually. However,
+ we should always sign over the ``$RID`` to ensure that the
+ resulting signatures are meaningful.
+
+ * When receiving an invoice (PULL payment request), we may want to
+ mandate a certain minimal set of attributes that *should* always
+ be included, and if that is absent warn the receiver that the
+ sender of the invoice did not properly identify themselves.
+
+ * By making this a new endpoint, the client can re-request
+ the signatures on-demand. This is useful if we use the
+ EdDSA online signatures of the exchange, which likely expire
+ long before the user changes their attributes.
+
+
+Closing reserves
+----------------
+
+ * This new endpoint ``/reserve/$RID/close`` allows the user to
+ force-close a reserve that has not yet expired. This is useful
+ in case invoices have been paid into the reserve and the
+ user wants to get their money out. The ``close`` endpoint
+ must be provided with an appropriate payto://-URI as
+ reserves that were filled by P2P merge operations may not
+ already have an associated bank account (empty ``reserves_in``
+ table).
+
+
+Alternatives
+============
+
+We could require the target account to be already specified on ``open``.
+However, that prevents people from invoicing that have no account (or we'd
+have to allow ``payto://void/``, which then prevents people from closing later
+if they got a bank account at a later stage).
+
+We could allow an amount to be specified on ``close`` to partially wire the
+funds in a reserve. However, reserves are not supposed to be used as bank
+accounts (either to wallet *or* exceptionally to bank account, please!), and
+this would conflict with the current implementation of the
+**taler-exchange-closer**. So no amount is likely better for minimal
+regulatory and implementation trouble.
+
+Closing a reserve could also prevent the future use of the reserve for
+invoicing. Right now, the specification allows this to continue, effectively
+allowing users to repeatedly close an account to drain its funds to a bank
+account instead of into a wallet.
+
+We could mandate a fixed set of attributes. However, it is unclear whether all
+exchanges will always have KYC providers enabled that offer any particular set
+of attributes. It is conceivable that some exchanges may not run with any kind
+of KYC, or just with phone-number validation, while others may require
+government IDs but not phone numbers. So we can easily end up with completely
+disjunct sets of attributes across operators.
+
+We could not warn users if *insufficient* attributes were provided in an
+invoice. However, that seems dangerous, especially as fake invoices are a
+common attacker trick.
+
+We could use attribute-based credentials (ABC) for the attestations. Benefits
+and (complexity) drawbacks of such a change should be discussed with Martin.
+
+
+Drawbacks
+=========
+
+Quite a bit of work to implement.
+
+
+Discussion / Q&A
+================
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/032-brandt-vickrey-auctions.rst b/design-documents/032-brandt-vickrey-auctions.rst
new file mode 100644
index 00000000..18660289
--- /dev/null
+++ b/design-documents/032-brandt-vickrey-auctions.rst
@@ -0,0 +1,312 @@
+DD 32: Brandt-Vickrey Auctions
+##############################
+
+Summary
+=======
+
+This document describes the design for how (SMC) auctions could be done with
+funds held in escrow by a Taler exchange. It is taking major inspiration from
+Markus Teich's Master's thesis on "Implementing Privacy Preserving Auction
+Protocols".
+
+The support for these types of auctions will be in the form of an extension for
+a deposit policy.
+
+
+Motivation
+==========
+
+Escrow is a key capability of payment systems. With SMC auctions we can
+broaden the escrow functionality beyond the (simplistic) refunds we currently
+offer. This provides a first new use-case for the extension mechanism. By
+using SMC auctions (libbrandt), we also provide privacy for another business
+process.
+
+We expect the design to be useful for three primary use-cases:
+
+ * Auctions in the style of Ebay (consumer goods)
+
+ * Auctions for commodities and stock trading
+
+ * Auctions in currency exchange, including crypto-currencies
+
+We do not consider the use-case of high-value art auctions, as here the Taler
+payment system is likely unsuitable for the high transaction values, the
+privacy for the buyer would still be problematic from a money-laundering
+perspective, and the cost of a trusted auctioneer manually running the auction
+is small compared to the transaction value, so the benefits from automation
+are also minor.
+
+
+Requirements
+============
+
+The discovery of ongoing auctions and the exchange of meta-data about the
+auction (duration, price ranges, conditions of the sale, etc.) is considered
+out-of-scope for the Taler protocol. Taler is only used to escrow a payment
+once participants have decided to make a bid on an aution.
+
+ * Support libbrandt-style SMC multiparty computation to determine
+ auction winner. No party is trusted to learn the bids during
+ the bidding phase, including the exchange. This implies that
+ participants have to always escrow the largest possible amount
+ in the auction, even if their actual bid is much lower.
+
+ * Integrate nicely with existing exchange functionality, including
+ minimal changes to existing endpoints and introducing as few new
+ endpoints as reasonable.
+
+ * Verifiablity of the auction outcome by the exchange and the
+ auditor. There is not supposed to be any trusted third party.
+ Naturally, when selling real-world goods, external enforcement
+ of the transfer of the good may be required.
+
+ * Guaranteed payment. If the auction is successful (there were at
+ least two bidders), the seller must unconditionally receive the
+ payment.
+
+ * Participants pay fees (possibly even just for participation),
+ to ensure only truly interested parties with skin in the game
+ participate (protection against denial-of-service attacks).
+
+ * To ensure participants can perform the required computations
+ in each round, the number of bidders on an auction may need
+ to be limited.
+
+
+
+Proposed Solution
+=================
+
+We will for now consider five types of parties involved in
+the auction:
+
+ * A seller, who is offering an item and who sets some basic
+ rules for the auction (like the price range, duration of
+ rounds, delivery conditions, seller's bank account,
+ auction operator, etc.).
+
+ * A number of bidders, who make bids on the auction, with
+ the highest bidder winnig the auction and paying the
+ second highest price to the seller.
+
+ * An auction operator, who collects messages from the seller
+ and the bidders and ultimately announces the (then universally
+ verifiable) outcome. In the original paper of Brand, this
+ would be the ``blackboard``. The auction operator may
+ also facilitate the discovery of auctions, but this is out
+ of scope. The auction operator may charge fees for setting
+ up and running an auction. However, from the Taler perspective,
+ paying an auction operator to run an auction is the same
+ as paying any other merchant and thus out of scope for this
+ design document.
+
+ * An exchange that supports the ``policy_vickrey_auction`` extension and
+ holds the funds for bids in escrow for the duration of the auction. Upon
+ completion of the auction, the exchange pays the seller from the auction's
+ winner and refunds the other bidders.
+
+ * An auditor that verifies that the exchange made the payments
+ correctly.
+
+The high-level protocol for a bidder's interaction with the auction operator
+and the Taler exchange is already described in Teich's thesis in Figure 3.2:
+the bidder begins by registering (say with an ephemeral EdDSA key) at the
+auction operator. Further messages from the bidder during this auction must
+then always be signed by the respective private key.
+
+The auction operator checks if there is a free slot (to limit the number of
+bidders per auction) and if one is free, gives the bidder a (modest) timeout
+until when it must prove that it escrowed an appropriate amount at the
+exchange. If no slots are free, the auction operator may allow the
+prospective bidder to long-poll for slots to become available (say because
+another prospective bidder failed to provide a proof of escrow on time).
+
+The bidder then uses the existing ``/deposit`` endpoint at the exchange to
+escrow the maximum bid. Escrowing the maximum bid ensures that no information
+about the actual bid is leaked to the exchange, and that any bid that could be
+made by the bidder can always be executed. In the ``/deposit``, the contract
+hash is set to information that includes those private parts of the auction
+meta data that do not concern the exchange (such as information about the item
+being sold). The seller's account information is included as the receiver of
+the funds. Additionally, the ``/deposit`` handler accepts an extension object
+which specifies the (SMC auction) extension and relevant meta-data about the
+auction (in particular, the bidder's ephemeral EdDSA public key, until when
+the auction runs, and (possibly) key material about the auction operator).
+
+The resulting proofs of deposits (plural, as there may be multiple coins
+involved) are then returned to the bidder. Note that the deposit confirmation
+signatures cover both the hash of the contract terms and the extension object.
+The deposit confirmations are then forwarded by the bidder to the auction
+operator, possibly already together with first (sealed) information about the
+bid.
+
+The auction operator then runs the auction protocol with all participants
+until conclusion. Once the winner and price have been determined, the auction
+operator POSTs the resulting transcript to a new
+``/extensions/policy_brandt_vickrey_auction`` endpoint of the exchange. Here,
+the extension-specific logic stores the transcript in its database (in a new
+table) and then simulates the auction again (using libbrandt), again
+determining the winner and price. The extension configuration (and thus
+``/keys``) may stipendulate some fee(s) charged by the exchange to handle the
+``/extensions/policy_brandt_vickrey_auction`` request. The fees should be
+covered by the seller. We note that the transcript inherently contains the
+deposit confirmations originally issued by the exchange for the auction. So,
+the exchange can identify all of the coins that were escrowed (it should also
+double-check that the coins were escrowed for the correct auction). It then
+refunds the bids from the losing bidders, pays the price to the seller from
+the winner (minus auction fee), and partially refunds the winner the difference
+between the escrowed amount and the winning bid.
+
+ .. note::
+
+ Partial refunds are currently implemented using the ``refunds`` table.
+ The refunds table requires refund message signatures by the merchant's
+ public key. Thus, this table will need to be generalized to include
+ some indicator as to whether the refund signature is valid or
+ whether some other mechanism justified the refund. The most trivial
+ way would probably be to allow NULL values for the signature. However,
+ likely a link to the extension transcript should then be stored in
+ another column to make it easier for the auditor to look for
+ "alternative" justifications in those cases.
+
+In case participants are identified as malicious, the auction meta data should
+specify the penalty those participants must pay to the seller. Again, the
+exchange should assess the auction transcript and then trigger the correct
+transactions.
+
+The auditor of the exchange can again simulate the auction protocol and can
+thus confirm that the exchange's ultimate transactions were correct.
+
+Transcripts
+^^^^^^^^^^^
+
+A transcript of a Brandt-Vickrey auction is the JSON encoding of an object of
+type `BrandtVickreyAuctionTranscript`.
+
+ .. ts:def:: BrandtVickreyAuctionTranscript
+
+ // This structure defines the transcript of an auction of Brandt-Vickrey kind.
+ interface BrandtVickreyAuctionTranscript {
+ // The auction definition.
+ auction: BrandtVickreyAuction;
+
+ // The public keys of the bidders, in Crockford Base32 encoding.
+ bidders: EddsaPublicKey[];
+
+ // Signatures of the auction in Crockford Base32 encoding.
+ // One signature per bidder.
+ signatures: EddsaSignature[];
+
+ // List of policy hash codes that identify policy details associated with
+ // each bidder. Those codes were generated by the policy extension
+ // policy_brandt_vickrey_auction during the deposit of coins for this
+ // auction.
+ policy_hash_codes: HashCode[];
+
+ // The transcript of all messages received by the seller.
+ transcript: BrandtVickreyAuctionMessage[];
+
+ // Optionally, the seller can provide the winners it had calculated.
+ winners?: BrandtVickreyAuctionWinner[];
+
+ // The signature over the hash of this JSON object, without the
+ // key ``sig`` and in normalized form, basically over
+ // H(auction, bidders, signatures, transcripts, winners?)
+ // It is signed by the private key that corresponds to the public key
+ // in `BrandtVickreyAuction`.``pubkey``.
+ // This signature is in Crockford Base32 encoding.
+ sig: EddsaSignature;
+ }
+
+
+ .. ts:def:: BrandtVickreyAuctionMessage
+
+ interface BrandtVickreyAuctionMessage {
+ // The index of the bidder into the
+ // `BrandtVickreyAuctionTranscript`.``bidders`` array.
+ bidder: number;
+
+ // The raw message in Crockford Base32 encoding.
+ msg: string;
+
+ // The signature over the message. The signature is in Crockford Base32
+ // encoding. It must be signed by the private key corresponding to the
+ // bidder's public key in `BrandtVickreyAuctionTranscript`.``bidders``.
+ sig: EddsaSignature;
+ }
+
+
+
+ .. ts:def:: BrandtVickreyAuctionWinner
+
+ interface BrandtVickreyAuctionWinner {
+ // The index of the bidder into the
+ // `BrandtVickreyAuctionTranscript`.bidder array.
+ bidder: number;
+
+ // The index of the winning price into the
+ // `BrandtVickreyAuction`.prices array.
+ price_idx: number;
+
+ // The winning price
+ price: Amount;
+ }
+
+
+Alternatives
+============
+
+If currency is sold for currency in an auction, the seller could also escrow
+the currency being sold. This could be done by a simple parallel extension
+for sellers that provides the seller's escrow proof as input into the auction
+protocol. The result would effectively be an auction-driven equivalent of the
+atomic swap protocols for crytocurrencies.
+
+Instead of the exchange and the auditor re-running the auction protocol
+internally against the transcript, it might suffice if the auction operator,
+seller and all bidders jointly attest to the outcome. However, this presumes
+that there are no malicious participants. Thus, this is an optimization that
+can help, but likely should not be relied upon. The exchange may stipendulate
+different fees if auction participants provide signatures demonstrating that
+they agree upon the outcome of the auction.
+
+
+Drawbacks
+=========
+
+Forcing participants to escrow the largest possible bid may exclude some
+bidders. However, it can be assumed that the seller (wanting to get as many
+high bids as possible) will set a reasonable bidding range to not exclude
+realistic bids. If the seller set the bidding range wrong and receives no bids
+as a result, the auction can of course simply be repeated. Finally, excluding
+bidders that can only make rather low bids may help keep the number of
+participants managable. Given the three application domains we focus on,
+it seems that the number of bidders regularly excluded from the auction due
+to this constraint should be acceptable.
+
+
+Discussion / Q&A
+================
+
+A possible challenge that may require more thought is how to deal with auction
+participants dropping out and not sending any more messages and the
+equivalent attack from the auction operator of suppressing messages from
+certain participants. The latter case can likely be addressed partially by
+network-level anonymization of all participants, as then the auction operator
+doesn't have the ability to target specific users. However, a conspirator
+could still deanonymize themselves to the auctioneer with the objective of the
+auction operator then suppressing messages from other (anonymous)
+participants and thereby possibly excluding higher bids from those users.
+
+ .. note::
+
+ As described above, the Master's thesis of Markus Teich proposes to
+ address the issue of bidders dropping out of the protocol by fining them,
+ for example by keeping (some of) the escrowed funds. This may work, but
+ only if we assume that the auction operator is not maliciously dropping
+ messages from some bidders.
+
+
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/033-database.rst b/design-documents/033-database.rst
new file mode 100644
index 00000000..ee37cc32
--- /dev/null
+++ b/design-documents/033-database.rst
@@ -0,0 +1,152 @@
+DD 33: Database Schema and Versioning
+#####################################
+
+Summary
+=======
+
+This document describes how we version database schema in GNU Taler
+and enable migrations.
+
+
+Motivation
+==========
+
+As Taler evolves, it will be necessary to add new tables, change existing
+tables, modify indices and make other changes to the database schema. As
+production systems exist, existing data will need to be migrated to the new
+schema, and we need to do this in a systematic way. While certain major
+changes may require radical or manual interventions, we should have a
+systematic way of dealing with minor or modest modifications to the schema.
+
+
+Requirements
+============
+
+* The approach should be language-independent
+* Schema migration should be reasonably performant
+* Schema migration must be usable, and in particular safe to use for
+ operators without significant risk
+* We need to support key database features we might need to use,
+ such as partitioning or sharding
+
+
+Proposed Solution
+=================
+
+We use the "versioning.sql" system to store the current set of patches that
+have been applied to the database so far in a "_v" schema. This allows us to
+quickly test which version of the database we are on and which migrations may
+still need to be applied.
+
+For each component, all tables are placed into a SCHEMA named after the
+component.
+
+We then use a set of numbered SQL files that create, alter or drop tables and
+indices (like exchange-0001.sql, exchange-0002.sql, ...) to setup the
+database. However, some setups need additional arguments, such as the number
+of partitions. Those setups are then NOT performed explicitly, but by creating
+stored procedures and registering those stored procedures in a general global
+"master" table to be called from the main setup logic with arguments in a
+particular order under certain conditions.
+
+When setting up a database, there is no point in incrementally defining
+ordinary stored procedures that are used at runtime (not the ones to setup the
+tables we talked about above). Thus, all of the stored procedures used by the
+runtime system are placed in a file "procedures.sql" which is loaded
+last. This makes changes to stored procedures particularly easy, as one simply
+edits "procedures.sql". Loading "procedures.sql" also does not change "_v".
+
+A "drop.sql" file is created that DROPs the main SCHEMA of the component and
+additionally unregisters all patches from the "_v" schema. The drop script
+is run during tests to fully reset the database.
+
+Exchange details
+^^^^^^^^^^^^^^^^
+
+The exchange uses "exchange_tables" to create the master
+table mentioned above. In "exchange_tables", entries are
+executed in the order of the "table_serial_id". Each
+entry has a "name", which is the name of the affected table
+(or at least the prefix in the case of partitioned or sharded
+tables). The "version" field stores which "exchange-XXXX.sql"
+file setup the respective table entry, but is for now mostly
+for internal documentation. The "action" defines both the
+condition under which to run a function. Specifically,
+actions can be:
+
+* create --- run on the master table and each shard; used to create or alter the main table
+* constrain --- run only on the partitions/shards, or on master if there are no partitions; used to setup constraints like uniqueness that only apply to the lowest levels of the table
+* master -- run only on the master table; used to setup triggers and other constraints that only apply to the master table
+* foreign -- run only on the master table and only if there are no partition; used to setup foreign key constraints that are not supported on partitioned or sharded tables
+
+The "partitioned" field indicates that this table is partitioned and instructs the functions to create partitions (or shards)
+for this table.
+
+The "by_range" field indicates if the table is partitioned by
+range, which prevents automatic generation of partitions as
+is done if partitioned by hash.
+
+The "finished" field is initially false, but set to TRUE once the respective
+function has been executed.
+
+The main "do_create_tables" function triggers the unfinished actions
+registered in the "exchange_tables" table. It is given arguments to control
+the number of partitions, the use of partitions and (in the future) the use of
+sharding.
+
+The individual actions use helper functions ("create_partitioned_table",
+"comment_partitioned_table" and "comment_partitioned_column") to facilitate
+the creation of tables and associated comments. These functions are used so
+that we can only define the schema or comment once, and have it applied to
+tables with names and creation syntax that changes slightly if we use shards
+or partitions.
+
+Some additional logic will be needed to deal nicely with
+sharding (which is currently not supported), as with
+sharing we will need to detach shards, migrate shards, and
+re-attach shards. So this will require additional stored
+procedures to support operations on shards.
+
+
+Merchant details
+^^^^^^^^^^^^^^^^
+
+The merchant does not (yet) need any type of master table, as we do not
+(yet) use any kind of sharding or partitioning. There are also no
+stored procedures being used by the backend. Hence, it is simply the
+"versioning.sql"-controlled table creation/alteration sequence
+(merchant-0001.sql, etc.) and the "drop.sql" to reset everything.
+
+
+Alternatives
+============
+
+* We might want to consider storing more meta-data
+ in the database, such as the use of sharding, the
+ names of the shard servers, or even just the number
+ of partitions.
+
+* We could require dumping out the old database and
+ loading it in via some explicit importer during each
+ migration; having migration logic in C would enable more
+ powerful migrations, but dumping and reloading the entire
+ database would also be more expensive. It would have the
+ advantage of basically having the old database around in
+ case of migration trouble, so the cost disadvantage might
+ not be so bad (as admins are likely to make a backup anyway).
+ OTOH, doing the migration with the equivalent of a
+ taler-auditor-sync would require quite a bit more code
+ than the simple ALTER/CREATE statements in an SQL file.
+
+
+Drawbacks
+=========
+
+* not exactly trival logic
+* some complexity to implement
+
+
+Discussion / Q&A
+================
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/034-wallet-db-migration.rst b/design-documents/034-wallet-db-migration.rst
new file mode 100644
index 00000000..e8cdb8c5
--- /dev/null
+++ b/design-documents/034-wallet-db-migration.rst
@@ -0,0 +1,78 @@
+DD 34: Considerations for Wallet Database Migrations
+####################################################
+
+Summary
+=======
+
+This design document discusses considerations for wallet database migrations.
+
+Motivation
+==========
+
+The schema of the GNU Taler Wallet database is evolving over time, either
+because new features are added or because bugs are fixed.
+
+Requirements
+============
+
+* Migrations may not result in data loss and must be automatic.
+* Our schema migration must be compatible with how IndexedDB works. This means that we can't
+ do arbitrary schema migrations at any time, but need to increment the IndexedDB database version
+ every time we add/remove/change an object store or index.
+
+Proposed Solution
+=================
+
+The schema of the wallet database is described in code in
+https://git.taler.net/wallet-core.git/tree/packages/taler-wallet-core/src/db.ts#n1959
+(``walletStoresV1``). This schema description is used to initialize and upgrade the
+database automatically.
+
+In IndexedDB terminology, the wallet has two databases:
+
+1. The ``"taler-wallet-meta"`` stores metadata about the current major-version database
+2. The major-version database (currently ``"taler-wallet-main-v9"`` stores the
+ actual data of the wallet.
+
+This indirection allows major database migrations to be safe despite the
+limitations of IndexedDB. The computation that is allowed during an IndexedDB
+migration is very limited. By migrating to a completely new database, we can
+keep around the old database until we're sure that the migration has succeeded
+and, if required, push new code to fix migration errors.
+
+We have three different mechanisms to introduce changes to the database:
+
+1. Major migrations. These migrations introduce a new major-version database and must manually
+ migrate the data from the previons major-version database. This migration should be
+ added in ``db.ts#openTalerDatabase``.
+ Major migrations should be used **very** seldomly. It can make sense to implement them
+ as a backup cycle, i.e. implement a backup export from the old version, upgrade to
+ the latest backup version and then re-import into the new major-version database.
+2. Minor schema migrations: These migrations add or remove object stores or indexes.
+ They are done by adding new elements to the schema descriptions **and** specifying
+ the ``versionAdded`` attribute. This causes an IndexedDB upgrade transaction
+ to be executed.
+3. Fixups. Fixups change data within or between minor schema versions and
+ contain arbitrary code to make changes to object stores. They are usually used
+ when a new mandatory field is added to an existing object store or some data
+ format changes. Fixups are also useful to retroactively fix bugs
+ introduced by previously deployed wallet versions.
+ They must be added to ``db.ts#walletDbFixups``
+
+Alternatives
+============
+
+* Per-object versioning instead of using IndexedDB minor versions
+* Always use the backup mechanism to upgrade the database
+
+ * Would be overkill for minor migrations
+
+Drawbacks
+=========
+
+N/A.
+
+Discussion / Q&A
+================
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/035-regional-currencies.rst b/design-documents/035-regional-currencies.rst
new file mode 100644
index 00000000..3d62dcc3
--- /dev/null
+++ b/design-documents/035-regional-currencies.rst
@@ -0,0 +1,196 @@
+DD 35: Regional currencies
+##########################
+
+Summary
+=======
+
+This design document discusses how the GNU Taler wallet can support both
+regional currency deployments and official fiat currencies.
+
+Motivation
+==========
+
+Digital cash in a Taler wallet always requires some kind of trust anchor that
+backs its value, be it either an exchange directly or an auditor that vouches
+for one or more exchanges.
+
+The currency code or symbol (EUR, USD, $, ...) is thus not enough to know what
+a particular wallet balance really means. It also matters what exchange or
+auditor is behind it. Thus the wallet needs some mechanism to allow users to
+distinguish between an official deployment of a currency (say EUR in Europe) or
+deployments of regional currencies. Regional currencies might have coinciding
+currency names for different incompatible deployments (say, MANA to buy Club
+Mate drinks at different hacker events with completely separate and independent
+Taler deployments).
+
+Requirements
+============
+
+* Official deployments for fiat currencies should be supported without clutter
+* Regional currencies should be easy to use as well
+* It must be easy to integrate regional/official currencies with the existing
+ Taler auditor/exchange structure
+* Wallet users should be able to see disagregated balance between global currencies
+ and regional currencies supported by different exchanges even if the currency
+ name is equal.
+* Merchants should be able to accept regional and global currencies based on the
+ supported exchange list.
+
+Proposed Solution
+=================
+
+Users usually do not want to see and verify the auditor/exchange URL for their
+digital cash. The wallet thus needs to support some form of "scope" for
+currencies that indicates the trust anchor for particular amounts and balances.
+
+The scope of a balance/amount gives the user additional information about the
+meaning and trust anchor of a balance/amount. The scope is always local and
+contextual to the wallet. Depending on the configuration, the wallet can show
+different scope information for the exact same coins.
+
+A balance is in exactly one of three scopes:
+
+1. Global. An amount in the global scope is by default displayed without
+ any additional qualification on the currency.
+2. Exchange-scoped. An exchange-scoped amount is always displayed with the
+ prettified base URL of the exchange.
+3. Auditor-scoped. An auditor-scoped amount is always displayed with the
+ prettified base URL of the auditor. When multiple auditors are applicable,
+ either the one with the lexically smallest base URL is chosen, or the
+ one that the user/wallet has configured as the prefered one for the currency.
+
+Whenever the wallet reports an amount, scope information should be
+present in the same message with the following format:
+
+.. code:: TypeScript
+
+ type ScopeInfo =
+ | { kind: "global" }
+ | { kind: "exchange", baseUrl: string }
+ | { kind: "auditor", baseUrl: string };
+
+Prettified base URLs
+^^^^^^^^^^^^^^^^^^^^
+
+The base URLs should be rendered without the ``https://`` and without
+trailing slashes:
+
+* ``https://exchange.demo.taler.net/`` would be rendered as
+ ``exchange.demo.taler.net``.
+
+* ``http://ex1.demo.taler.net/`` would be rendered as
+ ``http://ex1.demo.taler.net``.
+
+* ``https://ex2.demo.taler.net/foo/bar/`` would be rendered as
+ ``ex2.demo.taler.net/foo/bar``.
+
+
+Currency Scope Info in the Wallet
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For each configured currency code, the wallet should store following information:
+
+* List of global-scope exchanges and currencies for the currency. When this is an empty list,
+ the currency will always be shown with exchange/auditor scope info.
+
+Examples
+^^^^^^^^
+
+The following example shows how a wallet would render balances with
+global-scope EUR (i.e. a user would expect these to be "official" EUR that can
+be used with multiple vendors in Europe), two exchange-scoped MANA balances and
+one auditor-scoped MANA balance.
+
+.. code:: none
+
+ Balances:
+
+ 1.5 EUR
+
+ 3 MANA ([exchange-icon] exchange.leipzig.ccc.de)
+ 3.3 MANA ([exchange-icon] exchange.berlin.ccc.de)
+ 5 MANA ([auditor-icon] auditor.ccc.it]
+
+Scope information in requests for payments
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In wallet-to-merchant payments, the merchant specifies which exchanges and
+auditors the merchant accepts. It is desirable that the wallet renders the
+scope information for a requested amount in a similar way that a balance amount
+would be rendered.
+
+The amount should always be shown in the scope that is compatible with the
+merchant and that the wallet holds the highest amount in.
+
+Let's say a wallet has "auditor.ccc.it" as the global-scope auditor for MANA and holds
+mana audited by this auditor. A merchant accepts MANA from this auditor as well
+as from the exchange "mana.my-hackerspace.it".
+
+A payment request could then be rendered like this:
+
+.. code:: none
+
+ Summary: Club Mate (5x)
+ Amount: MANA:50
+
+
+If a wallet (by a non-Italian hacker) would not have "auditor.ccc.it" as the
+global-scope auditor for MANA, it would show as:
+
+.. code:: none
+
+ Summary: Cart #123 at Foomerchant
+ Amount: MANA:123 ([auditor-icon] auditor.ccc.it)
+
+ Other currencies supported by the merchant:
+ [exchange-icon] mana.my-hackerspace.it
+
+The last part should probably be hidden by default. There might be nicer ways to render
+this, such as some hoverable (?) icon after the amount that shows details about what currencies the merchant
+accepts.
+
+Wallet-core API for scope management
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* ``listGlobalCurrencyExchanges`` lists all ``(currency, exchangeUrl, exchangePub)`` triples
+ where funds are considered to be in global scope (i.e. non-regional).
+* ``listGlobalCurrencyAuditors`` lists all ``(currency, auditorUrl, auditorPub)`` triples
+ where funds are considered to be in global scope (i.e. non-regional).
+* ``addGlobalCurrencyExchange`` and ``removeGlobalCurrencyExchange`` adds/removes a ``(currency, exchangeUrl, exchangePub)``
+* ``addGlobalCurrencyAuditor`` and ``removeGlobalCurrencyAuditor`` adds/removes a ``(currency, auditorUrl, auditorPub)``
+
+
+Implementation Breakdown
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+* we need test currencies in each scope
+* wallet-core needs to add scope information to balances response
+ and various other requests
+* the UI needs to render those
+* wallet-core needs to expose new requests to manage currency information
+* the UI needs to allow the user to manage currency information
+
+
+Alternatives
+============
+
+* Completely distinguish regional currencies (non-three-letter currency code) and official currencies
+ (three letter ISO currency code). This does not help with overlapping regional currency names,
+ we can't expect them to be unique.
+
+Drawbacks
+=========
+
+* API and UI changes are required, but they can be made in an incremental and
+ backwards-compatible manner.
+* Scope information could be attached to the currency code.
+ That's a bad idea, because the scope information is totally local to the wallet.
+
+Discussion / Q&A
+================
+
+* Should we allow users to customize how scopes are displayed (e.g. an alias
+ instead of the full prettified base URL?)
+* Do we still need the auditor/exchange URLs with this proposal?
+* How does this affect the insufficient balance details? Should we also take scopes
+ into account here?
diff --git a/design-documents/036-currency-conversion-service.rst b/design-documents/036-currency-conversion-service.rst
new file mode 100644
index 00000000..92d88499
--- /dev/null
+++ b/design-documents/036-currency-conversion-service.rst
@@ -0,0 +1,97 @@
+DD 36: Currency conversion service
+##################################
+
+Summary
+=======
+
+This document explains the design of the currency conversion
+service. Such service enables customers to spend their fiat
+currency to buy Taler coins in a regional currency, and enables
+merchants to cash-out from the regional currency to fiat.
+
+Motivation
+==========
+
+The conversion service (CCS) is fundamental for a regional
+currency and is missing in the Taler/Libeufin ecosystem.
+
+Definitions
+===========
+
+*Fiat-issuer* is the fiat bank account that belongs to the regional currency
+issuer; typically, such bank account belongs to one association that runs the
+infrastructure. This bank account is hosted at the "fiat bank". *Regio-issuer*
+is the bank account that belongs to the local
+currency issuer but hosted at the bank that generates the regional currency.
+Such bank is also called "circuit bank". *Regio-exchange* is the bank account
+that belongs to the Taler exchange and that is hosted at the circuit bank.
+*Fiat-target* is a bank account hosted in the same currency of fiat-issuer
+and that belongs to a customer who initiated a cash-out operation. *Regio-user*
+is a bank account hosted at the circuit bank that is different from regio-issuer.
+*Fiat-customer* is a bank account hosted in the same currency of fiat-issuer,
+typically owned by customers that want to withdraw Taler coins in the regional
+currency.
+
+Requirements
+============
+
+* CCS must not impact the libeufin-nexus structure.
+* CCS must trigger Taler withdrawls every time a customer buys the
+ regional currency ('cash-in' operation).
+* CCS must offer cash-out operations.
+* CCS should react as soon as possible to cash-in and cash-out operations.
+* CCS must show its state to administrators and offer management tools.
+* CCS must link every fiat-side of a cash-out to its regional currency
+ counterpart. In particular, because every cash-out starts with a
+ payment *P* from regio-user to regio-issuer and ends with another
+ payment *Q* from fiat-issuer to fiat-target, CCS must link P and Q.
+
+Proposed Solution
+=================
+
+The following design assumes that CCS is coded in libeufin-bank and that
+libeufin-bank and libeufin-nexus share the same database with separate
+schemas. The solution relies on SQL triggers to atomically synchronise
+cash-in and cash-out operations between the two schemas.
+
+SQL triggers and conversion operations
+--------------------------------------
+
+Libeufin-bank controls the conversion support and sets up or removes
+conversion SQL triggers when necessary. In order for the SQL triggers to
+perform the conversion operations, the configurable rates/fees are stored
+in the database and the conversion operations are performed using stored
+SQL procedures. The SQL triggers and conversion procedures are stored in
+the libeufin-bank schema.
+
+Cash-out operation
+------------------
+
+Libeufin-bank learns instantly about a cash-out operation, because it's
+*the* service offering such feature. Therefore, as soon as a cash-out
+operation gets TAN-confirmed, libeufin-bank performs a wire transfer from
+regio-user to regio-issuer by specifying the amount without any rates/fees
+applied. Along the same database transaction, a SQL trigger store the
+*instructions* of another payment *P* from fiat-issuer to fiat-target,
+but this time **with** the cash-out rates/fees.
+
+Asynchronously, a libeufin-nexus background task picks P and sends it to
+the fiat bank. Finally, fiat bank conducts P and fiat-target receives the
+wanted amount. The same libeufin-nexus background task should also retry
+previous payments like P that failed to be submitted to fiat bank.
+
+Cash-in operation
+-----------------
+
+A cashin-in operation starts as soon as the customer sends a fiat
+payment from fiat-customer to fiat-issuer.
+
+The libeufin-nexus component is responsible to query the fiat bank
+via EBICS every X seconds. X should match the tightest interval allowed
+by the bank.
+
+When libeufin-nexus registers an incoming payment on fiat-issuer in the
+database, a SQL trigger applies the **current** cash-in rates/fees and
+performs a wire transfer from regio-issuer to regio-exchange. Libeufin-bank
+makes the exchange aware via the Taler Wire Gateway API and from now on,
+the system proceeds like it always did in Taler.
diff --git a/design-documents/037-wallet-transactions-lifecycle.rst b/design-documents/037-wallet-transactions-lifecycle.rst
new file mode 100644
index 00000000..535e4ff8
--- /dev/null
+++ b/design-documents/037-wallet-transactions-lifecycle.rst
@@ -0,0 +1,1049 @@
+DD 37: Wallet Transaction Lifecycle
+###################################
+
+.. contents:: Table of Contents
+ :depth: 2
+
+Summary
+=======
+
+This design doc discusses the lifecycle of transactions in wallet-core.
+
+Motivation
+==========
+
+The transactions in wallet-core all should have an associated state machine. All transactions
+should have some common actions that work uniformly across all transactions.
+
+Requirements
+============
+
+The underlying state machine should make it obvious what interactions
+are possible for the user. The number of possible user interactions
+in any state should be small.
+
+Proposed Solution
+=================
+
+
+Common States
+-------------
+
+The following states apply to multiple different transactions. Only pending
+and aborting have transaction-specific sub-states, denoted by ``state(substate)``.
+
+``pending``: A pending transaction waits for some external event/service.
+The transaction stays pending until its change on the wallet's material balance
+is finished. Any pending state can be suspended and resumed.
+
+There are some other distinctions for pending transactions:
+
+* long-polling vs. exponential backoff: A pending transaction is either waiting
+ on an external service by making a long-polling request or by repeating requests
+ with exponential back-off.
+* ``lastError``: A pending transaction is either clean (i.e. the network interaction
+ is literally active in transmission or the external service successfully
+ communicated that it is not ready yet and this is perfectly normal)
+ or has a ``lastError``, which is a ``TalerErrorDetails``
+ object with details about what happened during the last attempt to proceed
+ with the transaction.
+
+``done``: A transaction that is done does not require any more processing. It also
+never has a ``lastError`` but is considered successful.
+
+``dialog``: A transaction requires input from the user.
+
+``aborting``: Similar to a pending transaction, but instead of taking active steps to
+complete the transaction, the wallet is taking active steps to abort it. The ``lastError``
+indicates errors the wallet experienced while taking active steps to abort the transaction.
+
+``aborted``: Similar to ``done``, but the transaction was successfully aborted
+instead of successfully finished. It will have the information of when (timestamp) it was
+aborted and in which pending sub-state the abort action was initiated. Also, we can
+include more information information relevant to the transaction in ``abortReason``
+
+``suspended``: Similar to a ``aborted`` transaction, but the transaction was could be
+resumed and may then still succeed.
+
+``suspended-aborting``: Network requests or other expensive work
+to abort a transaction is paused.
+
+``failed``: Similar to ``done``, but the transaction could not be completed or
+possibly not even be aborted properly. The user may have lost money. In some
+cases, a report to the auditor would make sense in this state.
+
+``expired``: Similar to ``failed``, but the failure was caused by a timeout.
+
+``deleted``: A ``deleted`` state is always a final state. We only use this
+state for illustrative purposes. In the implementation, the data associated
+with the transaction would be literally deleted.
+
+
+Common Transitions
+------------------
+
+Transitions are actions or other events.
+
+``[action:retry]``: Retrying a transaction *(1.)* stops ongoing long-polling
+requests for the transaction *(2.)* resets the retry timeout *(3.)* re-runs the
+handler to process the transaction. Retries are always possible the following
+states: ``pending(*)`` and ``aborting(*)``.
+
+.. attention::
+
+ Should we show the retry timeout in the UI somewhere? Should we show it in dev mode?
+
+ SEBASJM: Since the wallet will retry anyway, maybe is better if we replace the "retry"
+ button with a "try now" button and a side text "retrying in xxx seconds".
+
+ CG: Instead of a side text, this *might* make a good mouse-over hint for
+ a "retry" (or "try now") button. I would not make this overly visible with
+ side-text as the information is not that important. The text should also be
+ "retrying next at XXX" using an absolute time XXX --- otherwise the UI would
+ be way too busy recomputing/updating all of these strings: Using an absolute time,
+ we only have to redraw anything once a retry actually happened. Given that
+ retries should basically never be > 24h (we can impose a hard cap), the absolute
+ time can just be in the format HH:MM:SS (without day).
+
+``[action:suspend]``: Suspends a pending transaction, stopping any associated
+network activities, but with a chance of trying again at a later time. This
+could be useful if a user needs to save battery power or bandwidth and an
+operation is expected to take longer (such as a backup, recovery or very large
+withdrawal operation).
+
+``[action:resume]``: Suspended transactions may be resumed, placing them back
+into a pending state.
+
+``[action:abort]``: Aborting a transaction either directly stops processing for the
+transaction and puts it in an ``aborted`` state, or starts the necessary steps to
+actively abort the transaction (e.g. to avoid losing money) and puts it in an
+``aborting`` state.
+
+``[action:fail]``: Directly puts an ``aborting`` or ``pending`` transaction into a
+``failed`` state. May result in an ultimate loss of funds (beyond fees) to the
+user and thus requires additional consent.
+
+``[action:delete]``: Deleting a transaction completely deletes the transaction
+from the database. Depending on the type of transaction, some of the other
+data *resulting* from the transaction might still survive deletion. For
+example, deleting a withdrawal transaction does not delete already
+successfully withdrawn coins. Deleting is only safe (no money lost) on initial
+and final states (failed, aborted, done).
+
+Whether aborting, deleting or suspending are possible depends on
+the transaction type, and usually only one of the four choices should be
+offered.
+
+
+.. image:: ../images/transaction-common-states.png
+
+
+Boxed labels indicate an end state in which there is no network activity and
+hence no need to give the user a way to abort or suspend the activity. The
+circle indicates the initial state. Ovals are states with network activity.
+
+Blue arrows are used for user-triggered actions (via UI buttons). Purple
+arrows are used to indicate externally triggered actions. Black arrows
+without labels are used for the normal successful path. Red arrows indicate
+failure paths.
+
+
+Common pending sub-states
+-------------------------
+
+During the pending state the transaction can go through several sub-states before
+reaching a final state. Some of this sub-states are shared between different
+transaction types:
+
+``kyc``: The transaction cannot proceed because the user needs to actively
+finish a KYC process. The wallet should show the user a hint on how to
+start the KYC process.
+
+``aml``: The transaction can't proceed because the user needs to wait for the
+exchange operator to conclude an AML investigation by the staff at the
+exchange. There are two AML substates. In the substate ``pending`` the user
+is not expected to take any action and should just wait for the investigation
+to conclude. In the substate ``frozen`` the staff at the exchange decided that
+the account needed to be frozen. The user should contact the exchange
+provider's customer service department and seek resolution (possibly through
+the courts) to avoid losing the funds for good.
+
+
+Transaction Type: Withdrawal
+----------------------------
+
+* ``pending(bank-register-reserve)``
+
+ Initial state for bank-integrated withdrawals. The wallet submits the reserve public key
+ and selected exchange to the bank (via the bank integration API). Note that if the
+ user aborts at this stage, we do not know if the bank is in the confirmation stage,
+ so we must still *try* to abort the transaction at the bank.
+
+ * ``[processed-success] => pending(bank-confirm-transfer)``
+ * ``[processed-error] => failed``: On permanent errors (like 404 for the withdrawal operation),
+ the wallet gives up.
+ * ``[action:abort] => aborting(bank)``
+
+* ``pending(bank-confirm-transfer)``
+
+ The wallet waits until the bank has confirmed the withdrawal operation;
+ usually the user has to complete a 2FA step to *approve* that the money is
+ wired to the chosen exchange. Note that the user's *approve* action is done
+ in the bank's user interface and not the wallet's user interface. The wallet
+ internally merely *polls* for the success or failure of the approve action.
+ The wallet **may** occasionally (after some initial delay, especially on
+ failures from the bank-poll to return any result) long-poll for the reserve
+ status and, if successful, may then directly jump to
+ ``pending(withdraw-coins)`` if the reserve is filled even if the poll at
+ the bank did not return success or failure.
+
+ * ``[bank-poll-success] => pending(exchange-wait-reserve)``
+ * ``[bank-aborted] => aborted``: Bank denied the operation.
+ * ``[exchange-poll-success] => pending(withdraw-coins)``: Optional
+ short-cut transition. Exchange was faster than the bank.
+ * ``[action:abort] => aborting(bank)``
+
+* ``aborting(bank)``
+
+ The user aborted the withdraw operation in the wallet. The wallet must now
+ try to signal the bank that the wire transfer should no longer be performed.
+ Note that it is possible that the bank registration never succeeded (if the
+ user aborted us during ``pending(bank-register-reserve)``) and in this case
+ we get an ``unknown transaction`` failure here. It is also theoretically
+ possible that the user approved the transaction in the bank while
+ simultaneously aborting in the wallet. In this case, we transition to
+ ``suspended(exchange-wait-reserve)`` (treating the ``abort`` action as a ``suspend``
+ action).
+
+ * ``[processed-success] => aborted``
+ * ``[processed-error(already-confirmed)] => suspended(exchange-wait-reserve)``: We
+ keep a transaction history entry reminding the user about when the already
+ wired funds will be returned.
+ * ``[processed-error(unknown-transaction)] => failed``
+
+* ``suspended(exchange-wait-reserve)``
+
+ State where funds were (presumably) wired to the exchange but the wallet
+ was asked to not proceed with the withdraw, but we still resume.
+
+ In this state, the wallet should show to the user that the money from the
+ withdrawal reserve will be sent back to the originating bank account after
+ ``$closing_delay``. Note that the ``resume`` action should be disabled
+ after ``$closing_delay``.
+
+ * ``[action:delete] => deleted``
+ * ``[action:resume] => pending(exchange-wait-reserve)``
+
+* ``pending(exchange-wait-reserve)``
+
+ Initial state for manual withdrawals. Here, the wallet long-polls the
+ exchange for the reserve status, waiting for the wire transfer to arrive
+ at the exchange.
+
+ * ``[exchange-poll-success] => pending(withdraw-coins)``
+ * ``[action:suspend] => suspended(exchange-wait-reserve)``
+
+* ``pending(withdraw-coins)``
+
+ State where we are finally withdrawing the actual coins. Depending on
+ the AML and KYC thresholds, we may at any time transition into a
+ holding pattern on the AML or KYC checks of the exchange.
+
+ It is possible that the selected denominations expired.
+ In that case, the wallet will re-select denominations.
+
+ * ``[processed-success] => done``
+ * ``[processed-kyc-required] => pending(kyc)``
+ * ``[processed-aml-required] => pending(aml)``
+ * ``[reserve-expired] => expired(reserve)``
+ * ``[action:suspend] => suspended(withdraw-coins)``
+
+* ``pending(kyc)``
+
+ State where the user needs to provide some identity data to pass a KYC
+ check. The wallet only shows the user the link for starting the KYC
+ process and long-polls the exchange in anticipation of the user
+ completing the KYC requirement.
+
+ * ``[poll-success] => pending(withdraw-coins)``
+ * ``[action:suspend] => suspended(kyc)``
+
+* ``suspended(kyc)``
+
+ State where the user needs to provide some identity data to pass a KYC
+ check, but the long-polling was explicitly stopped. The user can
+ choose to resume or delete.
+
+ * ``[action:delete] => deleted``
+ * ``[action:resume] => pending(kyc)``
+
+* ``pending(aml)``
+
+ State where the wallet needs to wait for completion of an AML process by an
+ AML officer of the exchange. The wallet shows that the AML process is
+ blocking progress. The message shown should distinguish between a mere
+ pending AML process and an AML freezing decision in terms of the message
+ shown to the user. If the AML decision is pending at the exchange, he user
+ should be urged to simply wait. If the funds were frozen, the wallet
+ informs the user that their funds were frozen due to an AML decision. The
+ user is urged to contact the exchange operator's AML department out-of-band.
+ In any case, the wallet long-polls for the AML decision to be made or change
+ (possibly at a lower frequeny in case of a freeze).
+
+ * ``[poll-success] => pending(withdraw-coins)``
+ * ``[action:suspend] => suspended(aml)``
+
+* ``suspended(aml)``
+
+ State where the user needs to await some AML decision by the exchange.
+ The long-polling was explicitly stopped. The user can choose to resume or delete.
+
+ * ``[action:delete] => deleted``
+ * ``[action:resume] => pending(aml)``
+
+* ``suspended(withdraw-coins)``
+
+ In this state, the wallet should show how much money arrived into the wallet
+ and the rest of the money will be sent back to the originating bank account
+ after ``$closing_delay``. Note that the ``resume`` action should be
+ disabled after ``$closing_delay``.
+
+ * ``[action:delete] => deleted``
+ * ``[action:resume] => pending(exchange-wait-reserve)``
+
+* ``done``
+
+ The withdrawal operation is complete.
+
+ * ``[action:delete] => deleted``
+
+* ``deleted``
+
+ Withdrawn coins are preserved, as is reserve information for recoup.
+ So this mostly removes the entry from the visible transaction history.
+ Only once all coins were spent, the withdraw is fully removed.
+
+
+.. image:: ../images/transaction-withdrawal-states.png
+
+
+Transaction Type: Payment to Merchant
+-------------------------------------
+
+* ``pending(claim-proposal)``
+
+ We received a ``pay`` URI. Download (claim) the proposal from the merchant. Can fail if
+ the proposal was already claimed by someone else. If repurchase detection
+ tells us that we already paid for this product, we go immediately to
+ ``failed(repurchase)`` state for this transaction, but with a side-effect of
+ transitioning the UI into a ``pending(repurchase-session-reset)`` on a
+ *different* transaction (which before was in ``done``).
+
+ A ``failed(repurchase)`` transaction will eventually be GCed (=deleted)
+ automatically.
+
+ * ``[error:already-claimed] => failed(already-claimed)`` -- the proposal was
+ already claimed by someone else.
+ * ``[error:invalid-proposal] => failed(invalid-proposal)`` -- the merchant provided a
+ proposal that is invalid (e.g. malformed contract
+ terms or bad signature).
+
+* ``dialog(merchant-order-proposed)``
+
+ Let the user accept (or refuse) the payment.
+
+ * ``[action:pay-accept] => pending(submit-payment)``
+ * ``[action:pay-refuse] => ``aborted(refused)`` -- The user explicitly
+ decided not to proceed (at least not with this wallet).
+ * ``[expired] => failed(expired)`` -- The offer has expired before the user made any
+ decision. Note that we should use this transition at
+ least a few seconds before the offer *actually* expires to avoid
+ encountering an expiration during ``pending(submit-payment)`` in most
+ real-world scenarios. Basically, we should prevent last-second payments to
+ be event attempted client-side.
+
+ The ``failed(expired)`` might be automatically deleted upon GC.
+
+* ``pending(submit-payment)``
+
+ Submit coin-by-coin (or in bulk groups) until payment is complete.
+
+ * ``[action:abort] => aborting(pay-incomplete)`` -- The user explicitly decided to
+ abort the process while the payment was happening. Note that if the
+ payment was already completed (and hence the merchant refuses any
+ refunds), it is theoretically possible that pressing the abort button will
+ nevertheless end up in a ``pending(auto-refund)`` state (and subsequently
+ a ``done`` state) instead!
+ * ``[success] => pending(auto-refund)`` -- Upon receiving confirmation from
+ the merchant that the purchase was completed.
+ * ``[error(insufficient balance)] => aborting(pay-incomplete)`` This transition
+ happens if we detect double-spending and our balance is not sufficient
+ after the double-spending. It is also conceivable (but should be rare)
+ that this transition happens because the offer expired.
+
+* ``pending(auto-refund)``
+
+ The payment succeed. We remain in this state as long as an auto-refund-check
+ is active. If auto refunds are not enabled, we immediately continue to
+ ``done``.
+
+ * ``[no-auto-refund] => done``
+ * ``[timeout] => done`` -- This happens when the auto refund set by the
+ contract expired.
+ * ``[long-poll:refund] => aborting(pay-incomplete)`` -- An auto-refund was detected.
+ * ``[action:abort] => done`` -- The user may explicitly request to abort the
+ auto-refund processing (for example to enable subsequent deletion before
+ the auto-refund delay expires).
+
+* ``aborting(pay-incomplete)``
+
+ The wallet should interact with the merchant to request
+ a refund on the incomplete payment.
+
+ * ``[success] => aborted(pay-incomplete)``
+ * ``[already-paid] => done``
+
+* ``aborted(refunded)``
+
+ The purchase ended with a (partial) refund. The state (and UI) should show
+ the specific provenance of the state, which may include an insufficient
+ balance (due to double-spending being detected during payment), and one or
+ more partial or full refunds.
+
+ * ``[action:delete] => deleted``
+
+* ``done``
+
+ The purchase is completed.
+
+ * ``[action:delete] => deleted``
+ * ``[repurchase] => pending(rebind-session)``: Another offer
+ became pending for this product and we need to update the session so
+ that the user does not have to buy it again.
+ * ``[check-refunds]` => pending(check-refunds)``: New refunds
+ might be available for this purchase.
+
+* ``pending(check-refund)``
+
+ New refunds might be available for this purchase.
+ This state must only be entered *after* the payment has successfully
+ completed. It is not relevant for auto-refunds or refunds for incomplete
+ payments.
+
+ * ``[refunds-checked] => pending(user-new-refund)`` --- New
+ refund(s) are available, user needs to confirm.
+ * ``[refunds-checked] => done`` --- Refunds were checked, but no
+ new refunds are available.
+ * ``[action:stop-refund-query] => done`` ---
+ This action would usually only be offered when the state is pending
+ with errors. It stops the refund query, but the payment of course
+ is left intact.
+
+* ``pending(rebind-session)``
+
+ The wallet should reset the associated session for the already purchased
+ (digital) item.
+
+ * ``[success] => done``
+ * ``[action:abort] => done`` -- User aborted the session reset.
+
+* ``deleted``
+
+ When a payment is deleted, associated refund transactions are always deleted
+ with it.
+
+.. image:: ../images/transaction-payment-states.png
+
+
+Transaction Type: Refund
+------------------------
+
+A refund is a pseudo-transaction that is always associated with a merchant
+payment transaction.
+
+* ``pending(accept)``
+
+ Initial state for a refund.
+
+ * ``[processed-error] => failed``: we received a permanent failure (such as money already wired to the merchant)
+
+* ``failed``
+
+ The refund failed permanently.
+
+.. image:: ../images/transaction-refund-states.png
+
+
+Transaction Type: Refresh
+-------------------------
+
+This is about refreshes that are triggered via coin expiration or as part of
+getting change after making a payment. In the first case, the refresh
+transaction is forever shown as a separate transaction in the history unless
+it did not affect the wallet balance (in which case we hide it). In the second
+case, the refresh transaction is folded into the payment transaction upon
+completion, so that the balance changes are included in the fees of the
+transaction that caused us to obtain change.
+
+If we have to adjust the refund amount (because a coin has fewer funds on it
+than we expect) the transaction only shows the changes due to the refresh, and
+we merely adjust the current balance of the wallet but without giving any
+justification (as we cannot give details we do not have). So this will look
+the same as if the double-spending transaction had been deleted by the user.
+
+* ``pending``
+
+ A refresh operation is pending.
+
+ * ``[processed-success] => done``
+ * ``[action:suspend] => suspended``
+ * ``[failed] => failed``
+
+* ``suspended``
+
+ A refresh operation was suspended by the user.
+
+ * ``[action:resume] => pending``
+
+* ``done``
+
+ The refresh operation completed.
+
+ * ``[action:delete] => deleted``
+
+* ``failed``
+
+ The refresh operation failed. The user lost funds.
+
+ * ``[action:delete] => deleted``
+
+* ``deleted``
+
+ All memory of the refresh operation is lost, but of course the resulting
+ fresh coins are preserved.
+
+.. image:: ../images/transaction-refresh-states.png
+
+
+Transaction Type: Deposit
+-------------------------
+
+* ``pending(deposit)``
+
+ Initial state for deposit transactions.
+ We deposit the amount coin-by-coin (or in bulk groups) until deposit is completed.
+
+ * ``[action:suspend] => suspended(submit-deposit)``
+ * ``[processed-success] => pending(track)``
+ * ``[processed-failure] => aborting(refund)``
+
+* ``suspended(deposit)``
+
+ The user suspended our ongoing deposit operation.
+
+ * ``[action:resume] => pending(deposit)``
+ * ``[action:abort] => aborting(refund)``
+
+* ``pending(track)``
+
+ All the coins were submitted, waiting to be wired.
+
+ * ``[poll-success] => done``
+ * ``[poll-accepted-kyc] => pending(kyc)``
+ * ``[poll-accepted-aml] => pending(aml)``
+ * ``[action:abort] => aborting(refund)``
+
+* ``pending(kyc)``
+
+ Exchange requires KYC before making the wire transfer.
+
+ * ``[long-poll:kyc] => done``
+ * ``[action:suspend] => suspended(kyc)``
+
+* ``suspended(kyc)``
+
+ The user suspended us while we were waiting for KYC to be finished.
+
+ * ``[action:resume] => pending(kyc)``
+
+* ``pending(aml)``
+
+ Exchange requires AML before making the wire transfer.
+
+ * ``[long-poll:aml] => done``
+ * ``[action:suspend] => suspended(aml)``
+
+* ``suspended(aml)``
+
+ The user suspended us while we were waiting for AML to be finished.
+
+ * ``[action:resume] => pending(aml)``
+
+* ``aborting(refund)``
+
+ Wallet should try to get the deposited amount back from the exchange (by submitting a refund).
+
+ * ``[action:suspend] => suspended(refund)``
+ * ``[processed-success] => aborting(refresh)``
+ * ``[processed-error] => aborting(refresh)``: Even if the refund attempt failed, maybe the deposit failed as well and we can still succeed with a refresh.
+
+* ``suspended(refund)``
+
+ The user suspended us while we were trying to get a refund.
+
+ * ``[action:resume] => aborting(refund)``
+
+* ``aborting(refresh)``
+
+ * ``[action:suspend] => suspended(refresh)``
+ * ``[processed-success] => aborted``
+ * ``[processed-error] => failed``
+
+* ``suspended(refresh)``
+
+ The user suspended us while we were trying to do the refresh.
+
+ * ``[action:resume] => aborting(refresh)``
+
+* ``aborted``
+
+ The operation was aborted, some funds may have been lost (to fees or deposited anyway).
+
+ * ``[action:delete] => deleted``
+
+* ``done``
+
+ The deposit operation completed.
+
+ * ``[action:delete] => deleted``
+
+* ``deleted``
+
+ All memory of the deposit operation is lost.
+
+.. image:: ../images/transaction-deposit-states.png
+
+
+Transaction Type: Peer Push Debit
+---------------------------------
+
+Peer Push Debit transactions are created when the user wants to transfer money
+to another wallet.
+
+States and transitions:
+
+* ``pending(purse-create)``
+
+ The wallet is creating a purse. Initial state.
+
+ * ``[process-success] => pending(ready)``: The wallet has created the purse.
+ * ``[process-failure] => aborting(refund)``: The purse creation failed.
+ * ``[action:suspend] => suspended(purse-create)``: The user suspended the operation.
+
+* ``suspended(purse-create)``
+
+ * ``[action:resume] => pending(purse-create)``: The user resumed the operation.
+ * ``[action:abort] => aborting(refund)``: The user aborted the operation.
+
+* ``pending(ready)``
+
+ In this state, the user can send / show the ``taler://`` URI or QR code to somebody else.
+
+ * ``[action:abort] => aborting(delete-purse)``: The user aborts the P2P payment. The wallet tries to reclaim money in the purse.
+ * ``[purse-timeout] => aborting(refresh)``: The other party was too slow and the purse has now expired.
+ * ``[poll-success] => done``: The other party has accepted the payment.
+ * ``[poll-error] => aborting(refresh)``: The exchange claims that there is a permanent error regarding the purse. (FIXME(CG): not clear that this is the best transition! Could also go to ``aborting(refund)`` or ``aborting(delete-purse)``; best choice may depend on the specific error returned.)
+
+* ``aborting(delete-purse)``
+
+ The wallet is deleting the purse to prevent the receiver from merging it and to reclaim the funds in it.
+
+ * ``[processed-success] => aborting(refresh)``: The purse was deleted successfully, and refunded coins must be refreshed.
+ * ``[processed-failed(already-merged)] => done``: The other party claimed the funds faster that we were able to abort.
+ * ``[processed-failed(other)] => aborting(refresh)``: The exchange reports a permanent error. We still try to refresh.
+ * ``[action:fail] => failed``: The user explicitly asked us to give up and accepted the possible loss of funds.
+
+* ``aborting(refund)``
+
+ We abandon the purse that was never fully funded and ask for the deposited coins to be refunded.
+
+ * ``[processed-success] => aborting(refresh)``: After the refund, we still need to refresh the coins.
+ * ``[processed-failure] => aborting(refresh)``: The refund failed, we still try to refresh the coins.
+ * ``[action:fail] => failed``: The user explicitly asked us to give up and accepted the possible loss of funds.
+
+* ``aborting(refresh)``
+
+ * ``[processed-success] => aborted``: Refresh group finished. Aborting was successful, money was reclaimed.
+ * ``[processed-failed] => failed``: Refresh group failed to complete with a permanent error.
+ * ``[action:fail] => failed``: The user explicitly asked us to give up and accepted the possible loss of funds.
+
+* ``done``
+
+ The transfer was successful.
+
+ * ``[action:delete] => deleted``
+
+* ``aborted``
+
+ The transfer was aborted. Except for fees, the money was recovered.
+
+ * ``[action:delete] => deleted``
+
+* ``failed``
+
+ The transfer failed. Money was lost. Unless on a forced abort, we should probably complain to the auditor.
+
+ * ``[action:delete] => deleted``
+
+* ``deleted``
+
+ All memory of the push debit operation is lost.
+
+.. image:: ../images/transaction-push-debit-states.png
+
+
+Transaction Type: Peer Push Credit
+----------------------------------
+
+Peer Push Credit transactions are created when the user accepts to be paid via
+a ``taler://pay-push`` URI.
+
+States and transitions:
+
+* ``pending(download)``
+
+ Wallet read the taler:// URI and is downloading the contract details for the user.
+
+ * ``[processed-success] => pending(user)``: Contract can be shown to the user.
+ * ``[action:suspend] => suspended(download)``: User suspended the operation.
+
+* ``suspended(download)``
+
+ The download of the purse meta data was suspended by the user.
+
+ * ``[action:resume] => pending(download)``
+
+* ``pending(user)``
+
+ User needs to decide about accepting the money.
+
+ * ``[action:accept] => pending(merge)``
+ * ``[timeout] => failed``: User took too long to decide.
+
+* ``pending(merge)``
+
+ * ``[processed-success] => pending(withdraw)``: Merging the reserve was successful.
+ * ``[kyc-required] => pending(merge-kyc)``: User must pass KYC checks before the purse can be merged.
+ * ``[timeout] => failed``: The purse expired before we could complete the merge.
+ * ``[failure] => failed``: The merge failed permanently.
+ * FIXME(CG): do we want to allow suspending here?
+
+* ``pending(merge-kyc)``
+
+ We cannot merge the purse until passing a KYC check.
+ The user is shown a hint where to begin the KYC
+ process and the wallet long-polls on the KYC status.
+
+ * ``[poll-success] => pending(withdraw)``
+ * ``[action:suspend] => suspended(kyc)``
+ * ``[timeout] => failed``: The purse expired before we could complete the merge.
+
+* ``suspended(merge-kyc)``
+
+ We cannot merge the purse until passing a KYC check,
+ and that check was suspended by the user.
+
+ * ``[action:resume] => pending(kyc)``
+ * ``[timeout] => failed``: The purse expired before we could complete the merge.
+
+* ``pending(withdraw)``
+
+ The wallet is withdrawing coins from the reserve that was filled by merging
+ the purse.
+
+ * ``[kyc-required] => pending(withdraw-kyc)``
+ * ``[aml-required] => pending(withdraw-aml)``
+ * ``[withdraw-failure] => failed``
+ * ``[withdraw-success] => done``
+ * ``[action:suspend] => suspended(withdraw)``
+
+* ``suspended(withdraw)``
+
+ The user requested the withdraw operation to be suspended.
+
+ * ``[action:resume] => pending(withdraw)``
+
+* ``pending(withdraw-kyc)``
+
+ We cannot withdraw more coins until passing a KYC check.
+ The user is shown a hint where to begin the KYC
+ process and the wallet long-polls on the KYC status.
+
+ * ``[poll-success] => pending(withdraw-coins)``
+ * ``[action:suspend] => suspended(withdraw-kyc)``
+
+* ``suspended(withdraw-kyc)``
+
+ We cannot withdraw from the reserve until passing a KYC check,
+ and that check was suspended by the user.
+
+ * ``[action:resume] => pending(withdraw-kyc)``
+
+* ``pending(withdraw-aml)``
+
+ We cannot withdraw more coins until AML rules are satisfied.
+ The user is shown a hint as to the AML status (pending or frozen).
+
+ * ``[poll-success] => pending(withdraw-coins)``
+ * ``[action:suspend] => suspended(withdraw-aml)``
+
+* ``suspended(withdraw-aml)``
+
+ We cannot withdraw from the reserve until AML rules are satisfied,
+ and the status check was suspended by the user.
+
+ * ``[action:resume] => pending(withdraw-aml)``
+ * ``[action:delete] => deleted``
+
+* ``failed``
+
+ The operation failed. Details are shown to the user. The money from the purse eventually goes to the sender (or some other wallet that merged it).
+
+ * ``[action:delete] => deleted``
+
+* ``done``
+
+ The operation succeeded.
+
+ * ``[action:delete] => deleted``: No money will be lost, the withdrawn coins will be kept
+
+* ``deleted``
+
+ All memory of the push credit operation is lost.
+
+.. image:: ../images/transaction-push-credit-states.png
+
+
+Transaction Type: Peer Pull Credit
+----------------------------------
+
+TODO: Also specify variant where account reserve needs to be created / funded first (Note: post 1.0-feature).
+
+* ``pending(purse-create)``
+
+ The wallet is creating a purse. Initial state.
+
+ * ``[process-success] => pending(ready)``: The wallet has created the purse.
+ * ``[process-failure] => deleted``: The purse creation failed. We only show a transient error.
+ * ``[action:abort] => deleted``: The user aborted the operation.
+
+* ``pending(ready)``
+
+ In this state, the user can send / show the ``taler://`` URI or QR code to
+ somebody else.
+
+ * ``[action:abort] => aborting(delete-purse)``: The user aborts the P2P payment.
+ * ``[purse-timeout] => aborted``: The other party was too slow and the purse
+ has now expired.
+ * ``[poll-success] => pending(withdraw)``: The other party has made the payment.
+ * ``[poll-error] => aborting(delete-purse)``: The exchange claims that there
+ is a permanent error regarding the purse. We should try to delete it.
+
+* ``aborting(delete-purse)``
+
+ We are cleaning up the purse after the operation failed or was aborted by
+ the user.
+
+ * ``[failure:already-merged] => pending(withdraw)``: Too late to abort, the
+ other side already paid the invoice.
+ * ``[process-success] => aborted``: The wallet has deleted the purse.
+ * ``[failure:other] => failed``: The purse deletion failed; we are
+ nevertheless done.
+ * ``[action:fail] => failed``: Money may be lost if it was deposited
+ into the purse in the meantime.
+
+* ``aborted``
+
+ The invoicing process ended without success.
+
+ * ``[action:delete] => deleted``
+
+* ``pending(withdraw)``
+
+ The wallet is withdrawing the money paid for the invoice.
+
+ * ``[processed-success] => done``
+ * ``[failure] => failed``
+ * ``[processed-kyc] => pending(kyc)``
+ * ``[processed-aml] => pending(aml)``
+ * ``[action:suspend] => suspended(withdraw)``
+
+* ``suspended(withdraw)``
+
+ The user suspended a withdraw operation.
+
+ * ``[action:resume] => pending(withdraw)``
+
+* ``pending(kyc)``
+
+ The user must supply KYC information before withdrawing can continue.
+
+ * ``[poll-success] => pending(withdraw)``
+ * ``[action:suspend] => suspended(kyc)``
+
+* ``suspended(kyc)``
+
+ The user suspended waiting for the KYC operation to complete.
+
+ * ``[action:resume] => pending(kyc)``
+
+* ``pending(aml)``
+
+ The user must await a positive exchange AML decision.
+
+ * ``[poll-success] => pending(withdraw)``
+ * ``[action:suspend] => suspended(aml)``
+
+* ``suspended(aml)``
+
+ The user suspended waiting for the AML decision to be successful.
+
+ * ``[action:resume] => pending(aml)``
+
+* ``failed``
+
+ Obtaining the money for the invoce failed. This is likely a case for the
+ auditor.
+
+ * ``[action:delete] => deleted``
+
+* ``done``
+
+ The payment for the invoice was successfully received.
+
+ * ``[action:delete] => deleted``
+
+* ``deleted``
+
+.. image:: ../images/transaction-pull-credit-states.png
+
+
+Transaction Type: Peer Pull Debit
+---------------------------------
+
+* ``pending(download)``
+
+ We are downloading the information about the invoice. Initial state.
+
+ * ``[action:suspend] => suspended(download)``
+ * ``[success] => pending(user)``
+
+* ``suspended(download)``
+
+ User suspended downloading the information about the invoice.
+
+ * ``[action:resume] => pending(download)``
+ * ``[action:delete] => deleted``
+
+* ``pending(user)``
+
+ We have downloaded information about the pull payment and are waiting for
+ the user to confirm.
+
+ * ``[action:confirm-pay] => pending(submit-payment)``
+ * ``[action:delete] => deleted``
+ * ``[timeout] => aborted``
+
+* ``pending(deposit)``
+
+ The user has confirmed the payment and the wallet tries to deposit
+ into the provided purse.
+
+ * ``[action:suspend] => suspended(deposit)``
+ * ``[processed-success] => done``
+ * ``[failure:timeout] => aborting(refresh)``
+ * ``[processed-success] => done``
+ * ``[failure:other] => aborting(refund)``
+
+* ``suspended(deposit)``
+
+ User suspended depositing into the purse.
+
+ * ``[action:resume] => pending(deposit)``
+ * ``[action:abort] => aborting_refund``
+
+* ``aborting(refund)``
+
+ Aborts the payment, asking for the already deposited coins to be refunded.
+
+ * ``[processed-success] => aborted(refunded)``
+ * ``[processed-failure] => aborting(refresh)``
+ * ``[action:fail] => failed``
+
+* ``aborting(refresh)``
+
+ Refreshes the coins that were previously deposited into the purse to recover their value.
+
+ * ``[processed-success] => aborted``
+ * ``[processed-failed] => failed``
+
+* ``done``
+
+ The invoice was successfully paid.
+
+ * ``[action:delete] => deleted``
+
+* ``deleted``
+
+ All information about the invoice has been deleted.
+
+.. image:: ../images/transaction-pull-debit-states.png
+
+Alternatives
+============
+
+* Each transaction could be treated completely separately; however, uniform
+ terminology for actions (and thus button labels) is likely more helpful for
+ the user experience.
+
+* We could require user re-approval if fees changed when the available
+ denominations change during a *withdraw*. This would require a different
+ state machine on withdraw. We believe the answer can be "no", for two
+ reasons: the wallet MUST pick denominations to withdraw with the "most
+ long-term" withdraw window (i.e. active denominations that have the longest
+ available withdraw durations). So in virtually all normal cases, this will
+ just succeed as a sane exchange will have a reasonable duration overlap, and
+ in the very few cases it's really the user's fault for going offline in the
+ middle of the operation. Plus, even in those few cases, it is highly
+ unlikely that the fee would actually change: again most key rotations can be
+ expected to be there to rotate the key, and not to adjust the withdraw fee.
+ And in the extremely rare case that the user went offline and in the
+ meantime the fees did *increase*, it's again unlikely to matter much to the
+ user. So special-casing this and testing this is probably not worth it.
+
+* We could require user re-approval if due to expired/invalid coins the coin
+ selection (and thus fees) changes during a *deposit*. Again, expired coins
+ should virtually never happen unless a user goes offline for a long time in
+ the middle of a purchase (which would be very strange). If deposit fees
+ *increase* due to a double-spend detection during payment, we might want to
+ have an *optional* dialog ("Balance reduced by X as wallet state was not
+ up-to-date (did you restore from backup?). Consequently, the fees for this
+ transactions increased from Y to Z. [Abort] [Continue] + checkbox: [X] Do
+ not ask again."). Probably at best a post-1.0 feature.
+
+
+Discussion / Q&A
+================
+
+* The diagrams only show what is happening **after** the wallet
+ has created the transaction. It is possible that network requests
+ are happening before that, but they are not considered to be part
+ of the transaction.
+* We have decided against a ``cancel`` state, because it resulted
+ in too much complexity. Instead of doing a direct ``cancel``,
+ the user has to go to the transaction and abort and/or delete
+ it.
+* We might add a ``revive`` action in the future that allows
+ to go from ``aborting`` back to ``pending`` for transactions
+ where this makes sense. We're not doing it right now
+ to simplify things.
diff --git a/design-documents/038-demobanks-protocol-suppliers.rst b/design-documents/038-demobanks-protocol-suppliers.rst
new file mode 100644
index 00000000..ee8fdc09
--- /dev/null
+++ b/design-documents/038-demobanks-protocol-suppliers.rst
@@ -0,0 +1,158 @@
+XX 38: Demobanks protocol suppliers
+###################################
+
+Summary
+=======
+
+This document models the association between financial data
+held in a LibEuFin *demobank* and the interface to let users
+access such financial data.
+
+Motivation
+==========
+
+LibEuFin Sandbox offers multitenency banking by the means of
+'demobanks'. Each demobank offers access to financial data via
+*several* APIs. The objective is to model such APIs so that each
+operation impacts one and only one demobank.
+
+Definitions
+===========
+
+Each API to access financial data at one demobank is offered by
+a **resource** called *protocol supplier*. Therefore protocol
+suppliers MAY be subject to all the CRUD operations
+
+For each request that a protocol supplier serves, the demobank
+being impacted can be found in the following ways:
+
+.. _demobank-mutually-exclusive:
+
+1. In a value that belongs to the request.
+2. In a value that belongs to the protocol supplier's state.
+3. Relying on the default demobank.
+
+Note: the three elements are mutually exclusive, so as to reduce
+ambiguity and simplify the implementation.
+
+Suppliers creation
+==================
+
+Suppliers can be static or dynamic.
+
+Static
+^^^^^^
+
+This supplier never changes its state. Whether this type
+of supplier is associated or not with a particular demobank
+MUST be stated in the documentation.
+
+Examples
+--------
+
+1. A JSON-based protocol that lets users access their bank accounts
+always under the 'default' demobank belongs to this category. It
+is therefore a 'static protocol supplier' with static demobank.
+
+2. A XML-based protocol that lets users access their bank accounts
+in a demobank whose name appear in the URI is as well a 'static protocol
+supplier' with dynamic demobank.
+
+Note: the upcoming (in version 0.9.3) JSON-based supplier that will
+let Nexus reach Sandbox accounts is planned as a 'dynamic protocol
+supplier' with dynamic demobank. That allows Taler demos to only
+speak JSON.
+
+Dynamic
+^^^^^^^
+
+This supplier has a name and its state CAN refer to one
+particular demobank. These suppliers need to be created
+first, in order to be used.
+
+Examples
+--------
+
+1. A JSON-based protocol that lets users access their bank
+accounts under the demobank whose name is held in the supplier
+state belongs to this category. It is therefore a dynamic
+supplier with semi-dynamic demobank.
+
+2. A XML-based protocol that lets user access their bank
+accounts under the demobank whose name is held both in the
+supplier state *and* in the URI is **wrong**. This supplier
+doesn't respect this `mutual exclusivity <demobank-mutually-exclusive_>`_.
+
+3. A XML-based protocol that lets user access their bank accounts
+always under the 'default' demobank belongs to this category. It
+is a dynamic supplier with static demobank.
+
+Supplier reachability
+=====================
+
+Each supplier must be available under its own URI.
+
+
+Current protocol suppliers design
+=================================
+
+Static X-LIBEUFIN-BANK with dynamic demobank
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``x-libeufin-bank`` protocol supplier is reachable under
+``/demobanks/{demobankName}/access-api/``. As the path suggests,
+it offers banking operations via the :doc:`Core Bank API </core/api-corebank>`.
+It is static in the sense that it's not possible to assign a name
+to one particular x-libeufin-bank protocol supplier. On the other
+hand, the demobank is dynamic because can be specified along the path
+in the ``demobankName`` placeholder.
+
+Dynamic EBICS supplier with dynamic demobank
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Every protocol supplier of this type is reachable under ``POST /ebicsweb``
+and by specifying its EBICS host name inside the EBICS message.
+
+As of the internal representation, Sandbox keeps a database table called
+``EbicsHostsTable`` that does **not** point at any demobank. Such table
+is the one that provides the bank's EBICS private keys and has **no** business
+implications.
+
+CCT (Payment initiations)
+-------------------------
+
+This handler gets the bank account directly from the IBAN that was
+carried along the pain.001, therefore -- as long as every IBAN is
+unique -- this works with **any** demobank that hosts such IBAN. The
+EBICS subscriber public keys are extracted differently: they come from
+the tuple [userID, partnerID, systemID?] held in the request. Hence as
+long as such tuple is unique for each subscriber (Sandbox checks that),
+even the subscriber public keys are found regardless of the demobank name.
+
+.. note::
+
+ The 'context' object found via the [userID, partnerID, systemID?] tuple
+ has **also** a reference to the bank account. The consistency with the
+ other bank account reference returned by the IBAN is currently NOT checked.
+
+C52 (transactions report)
+-------------------------
+
+This handler gets the reference to the subscriber public keys and bank
+account via the [userID, partnerID, systemID?] tuple. It then uses
+this bank account label to find the transactions that belong to the
+subscriber that made the request.
+
+.. note::
+
+ The current implementation does NOT uses any demobank name along
+ the transactions research: only the bank account label. This can
+ lead to **ambiguity**, in case two different demobanks host respectively
+ one bank account under the same label. This is not possible however
+ in the current version, as Sandbox only admits one ``default`` demobank.
+
+
+Alternatives
+============
+
+Drop support for multitenancy banking. What is the benefit of this anyway?
diff --git a/design-documents/039-taler-browser-integration.rst b/design-documents/039-taler-browser-integration.rst
new file mode 100644
index 00000000..980f3f25
--- /dev/null
+++ b/design-documents/039-taler-browser-integration.rst
@@ -0,0 +1,195 @@
+DD 39: Taler Wallet Browser Integration Considerations
+######################################################
+
+Summary
+=======
+
+This design document discusses considerations for integrating the GNU Taler
+wallet with browsers and highlights difficulties with the implementation of a
+GNU Taler wallet as a cross-browser WebExtension.
+
+Motivation
+==========
+
+GNU Taler is a payment system based on open standards with a free and open
+source reference implementation. The GNU Taler wallet is the main component
+used by end users to manage their electronic cash balance and payments.
+
+Payments with GNU Taler are typically initiated via a QR code or link that
+contains a ``taler://pay/{merchant}/{order_id}`` URI. Navigating to such a
+link should result in a context switch to the wallet, where the payment can can
+be approved/declined, and the user is subsequently redirected to the merchant's
+website again.
+
+Other ``taler://`` URIs (for withdrawals, refunds, etc.) are also commonly
+used, but not explicitly discussed in this document, as very similar
+considerations apply.
+
+There are multiple reference implementations available for multiple
+platforms (command line, Android, iOS, WebExtension).
+
+While native applications can register themselves as a handler for the
+``taler`` URI scheme, the story is different for WebExtensions: There is
+currently no reasonable, cross-platform mechanism that allows a WebExtension to
+register itself as the handler for the ``taler`` URI scheme.
+
+This is unfortunate, as a WebExtension could otherwise easily provide a Taler
+wallet implementation without requiring the user to install a native App,
+providing a better and safer user experience.
+
+The problems with individual browsers are:
+
+* Firefox allows specifying ``protocol_handlers`` in the extension manifest.
+ However, this list only allows schemes with the prefix ``ext+`` and
+ schemes that are included in an allowlist. The ``taler`` URI scheme
+ is not part of this list yet.
+* Chromium / Google Chrome allows extensions to use the
+ ``registerProtocolHandler`` API. However, the same allowlist restrictions
+ apply. Furthermore, the registered protocol scheme is not listed as the
+ extension's required/optional permissions. Instead, a different permission
+ prompt is dynamically shown to the user.
+* Safari currently neither supports ``registerProtocolHandler`` nor the
+ ``protocol_handlers`` mechanism.
+* Opera does not seem to have any support for WebExtension protocol handlers
+ either.
+
+Another issue is that Websites can't easily find out whether a browser
+extension handling the ``taler://`` protocol is installed.
+
+Requirements
+============
+
+* No vendor lock-in: The integration should not require merchant
+ Websites to rely on a particular list of extension IDs but instead
+ any WebExtension to potentially handle ``taler://`` URIs
+ or other mechanisms that Websites can use to interact with Taler
+ wallets.
+* Security: The integration mechanism should require as few
+ permissions as possible.
+* Ergonomic user experience: As few clicks and permission
+ prompts as possible should be shown to the user.
+* Ergonomic developer experience: The code size and
+ effort to trigger a Taler payment on a merchant's Website
+ should be minimized.
+* Forward compatibility: The integration mechanism
+ should work smoothly with future browsers that
+ have native, built-in support for Taler payments.
+
+Proposed Solution
+=================
+
+.. note::
+
+ As of 2023-01-23, we've decided to go ahead with the approach
+ described in this section.
+
+Overview
+^^^^^^^^
+
+The following integration approaches between Websites and the Taler Wallet webextension
+are provided:
+
+1. Directly triggering a ``taler://...`` URI on page load (via a meta tag).
+2. Overriding ``<a href="taler://..." onclick=...>`` tags to trigger the wallet.
+ The onclick handler (which must call preventDefault) can implement behavior
+ that happens only when the webextension is not available.
+3. Future (possibly post-1.0): A ``window.taler`` JavaScript API that is injected
+ into every page that requests it via a meta tag. This is useful for SPAs that
+ want to programmatically trigger the Taler wallet.
+
+
+Usage
+^^^^^
+
+To directly trigger the handling of a ``taler://`` URI on page load, the following meta tag can be used:
+
+.. code::
+
+ <meta name="taler-uri" content="taler://...">
+
+
+To enable additional communication features between a website and the GNU Taler Wallet webextension, the page must
+include the following meta tag:
+
+.. code::
+
+ <meta name="taler-support" content="$features">
+
+where ``$features`` is a comma-separated list of features.
+
+The following features are supported:
+
+* ``uri`` will hijack anchor elements (``<a href="taler://..." onclick=...>``) and replace their onclick handler
+ with a different handler that lets the webexension wallet handle the ``taler://`` URI.
+
+* (future): ``api`` will inject the ``window.taler`` API into the page
+
+
+Caveats and Comments
+^^^^^^^^^^^^^^^^^^^^
+
+* Anchor tag hijacking does not work in all use-cases, for example when a navigation
+ to a ``taler://`` URI is initiated programmatically or by pasting
+ the URI in the browser's address bar.
+
+* The ``window.taler`` API injection may break some websites
+ (https://github.com/brave/browser-laptop/issues/13711).
+
+* All these approaches require excessive permissions, as unfortunately,
+ browsers currently do not provide a safe way for the communication between a
+ WebExtension and the page without excessive permissions. This especially
+ applies if the Website does not know the extension's ID. Hard-coding the
+ extension IDs would violate the "no vendor lock-in requirement".
+
+* A neat feature of the anchor hijacking is that the ``taler://`` URI can be always be copied
+ in the browser (via "copy link address"). Clicking the link always results in either:
+
+ * The native URI handler, if no Taler Wallet webextension is installed and no onclick handler is defined
+ * The execution of the websites onclick handler if no Taler Wallet webextension is installed
+ * Triggering the webextension wallet to handle the ``taler://`` URI.
+
+* Future ``window.taler`` injection should be based on user preferences on
+ sites where the user has explicitly accepted to disclose that is owner of a
+ Taler wallet.
+
+Other Alternatives
+==================
+
+
+* Triggering interactions with the ``taler://`` URI in a ``Taler:`` HTTP
+ header. This approach would allow browsers with native Taler support
+ (or a WebExtension) to handle payment/withdrawal initiations directly,
+ without rendering a page that shows the QR code or link.
+ However, the WebExtension APIs do not allow extensions to
+ read particular headers without excessive permissions. Furthermore,
+ more recent versions of Chrome/Chromium do not allow blocking
+ processing of headers, leading to flickering when the extension
+ redirects based on the presence of the ``Taler:`` header.
+
+* Browser and wallet presence detection. Merchants' Websites could include custom
+ code to detect the browser and/or presence of a Taler WebExtension and show
+ different instructions to guide the user towards processing the payment or to
+ show ``ext+taler`` URIs instead of ``taler`` URIs. This is not a viable
+ solution, as it requires a lot of extra and brittle logic on merchants'
+ Websites.
+
+* Always use ``ext+taler`` URIs. This would help with Firefox.
+ Bad for forward compatibility, as we have already provisionally registered the
+ ``taler`` URI scheme.
+
+* Web Payments API: Using the Web Payments API is not possible, because current
+ browsers do not allow specifying a WebExtension as a handler. Furthermore,
+ the Web Payments API would not support the withdrawal flow
+ (``taler://withdraw`` URIs).
+
+* Browsers could provide anchor elements with a fallback when the protocol isn't supported, such as
+ ``<a href="taler://pay/..." handler-unavailable-href="https://wallet.taler.net/">...</a>``.
+
+
+
+Related Work and References
+===========================
+
+* **[1]** https://github.com/whatwg/html/issues/8596
+* **[2]** https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/protocol_handlers
+* **[3]** https://github.com/ipfs/devgrants/blob/master/targeted-grants/protocol-handler-api-for-browser-extensions.md
diff --git a/design-documents/040-distro-packaging.rst b/design-documents/040-distro-packaging.rst
new file mode 100644
index 00000000..13131359
--- /dev/null
+++ b/design-documents/040-distro-packaging.rst
@@ -0,0 +1,139 @@
+DD 40: Distro Packaging
+#######################
+
+.. admonition:: Metadata
+
+ Status
+ proposed
+
+Summary
+=======
+
+This DD discusses considerations for disto packages of GNU Taler components,
+especially with regards to configuration and setup. We focus on Debian
+packages for now.
+
+Motivation
+==========
+
+The current way that configuration files are handled does not work well with
+automated setup tools and furthermore does not easily allow restoring
+configuration files in ``/etc/`` that the admin deleted or manually modified.
+
+The database configuration is currently handled inconsistently. While some
+packages use Debian's dbconfig-common facilities, others don't, even though
+they require a database for operation.
+
+The guidelines in this document are based on pratical experience
+with third parties setting up Taler based on the Debian packages
+and scripting supplied by us (i.e. ``deployment.git/netzbon``).
+
+Requirements
+============
+
+* The distro package should work nicely both for a manual setup
+ process by a sysadmin, as well as for automated installation
+ via helper scripts or other tools.
+* Major differences between different distributions should be minimized, the
+ more code and config templates that can be shared the better.
+
+Proposed Solution
+=================
+
+This section contains the new guidelines that we want to apply to all our
+distro packages, specifically the Debian packages.
+
+General Considerations
+----------------------
+
+* Packages may not enable a systemd service by default.
+
+Config Files: Taler-specific
+----------------------------
+
+The "pristine" version of config files must be installed into
+``/usr/share/taler/etc-original``. These files should not be modified by
+tooling or the user. These files may contain direct placeholders or
+placeholder comments that are replaced (but not in-place, only in ``etc/``!)
+when the package is configured.
+
+During the postinstall step, the files from ``/usr/share/taler/etc-original``
+are copied to ``/etc/`` (using the ``ucf`` tool on Debian) and, if required,
+placeholders are filled in.
+
+When using tooling to set up Taler, the tooling **should not**
+use files from ``/etc/`` as template, but instead from ``/usr/share/taler/etc-original`` or alternatively generate custom configuration files.
+
+Rationale: Debian manages conffiles in ``/etc/`` with special logic.
+In particular, when files are deleted from ``/etc/taler`` and the package
+is reinstalled (even with ``--reinstall``), there is no easy way for
+tooling (or the admin) to restore the unmodified config files.
+The only way to restore it is ``apt install --reinstall libtalerexchange -o Dpkg::Options::="--force-confmiss"``, which might be unsafe as it forces
+overriding of *all* config files of the package.
+
+Config Files: HTTP Server
+-------------------------
+
+The same considerations apply to configuration files of HTTP
+servers (nginx, apache, caddy, ...). Additionally:
+
+* Configuration files *must* either have a well-known name
+ or particular suffix to easily identify them
+
+ * In particular, file names like ``sites-available/exchange.$domain``
+ are unacceptable, as they are very difficult to uninstall
+ or remove when ``$domain`` is changed.
+
+* Configuration files for the HTTP server must not be
+ active by default, i.e. they must be placed in ``sites-available``
+ but not ``sites-enabled``.
+
+Database
+--------
+
+Packages should *not* use ``dbconfig-common``. Reasons are:
+
+* ``dbconfig-common`` is lacking in documentation and very difficult
+ to use for packagers.
+* ``dbconfig-common`` offers too much flexibility and
+ asks too many questions to the administrator, especially when
+ reconfiguring a package. The ``taler-merchant`` package
+ currently breaks when the user chooses anything else than ``ident`` auth.
+* Using ``debconfig-common`` makes the database setup logic difficult to test.
+ That is not a problem with simple packages, but most Taler packages
+ require a non-trivial database setup.
+* Very few packages in Debian (<30) actually use ``dbconfig-common``;
+ even fewer are notable or widely used packages.
+
+Instead, each package should document how to set up
+the database and *optionally* ship an executable named
+``taler-$component-dbconfig`` that:
+
+1. Creates the database and adjusts permissions
+2. Checks if the database is accessible
+3. Runs ``taler-$component-dbinit`` if applicable
+ and unless supressed by the user.
+
+For now, our tooling shall only support PostgreSQL and only set up ``ident``
+authentication or set up ``password`` authentication with a random password for
+components that do not support DB connections via unix domain sockets.
+
+Definition of Done
+==================
+
+* All Taler and Anastasis packages follow the guidelines from this DD
+* Packages installation has been manually tested
+* Automated setup scripts (``deployment.git``) have been adjusted to use the
+ configuration file templates shipped in the package,
+ instead of using their own config templates.
+
+Alternatives
+============
+
+* Do not ship with distro-specific configuration files, instead only ship
+ tooling to generate config files and set up the database.
+
+Discussion / Q&A
+================
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/041-wallet-balance-amount-definitions.rst b/design-documents/041-wallet-balance-amount-definitions.rst
new file mode 100644
index 00000000..9943d482
--- /dev/null
+++ b/design-documents/041-wallet-balance-amount-definitions.rst
@@ -0,0 +1,410 @@
+DD 41: Wallet Balance and Amount Definitions
+############################################
+
+Summary
+=======
+
+This design document discusses terminology and concepts used in the wallet
+for balances and amounts.
+
+Motivation
+==========
+
+There are many different types of balances and amounts, and they need
+to have a clear definition.
+
+Furthermore, the user in some situations needs to know/decide whether
+an amount that the user chooses includes fees or not.
+
+
+Proposed Solution
+=================
+
+Amounts
+-------
+
+* "effective amount": An effective amount always represents the direct effect on the
+ wallet's balance of the same currency.
+* "raw amount": The raw amount always refers to the amount with fees applied.
+ The exact interpretation of that depends on the transaction type.
+* "instructed amount": An instructed amount always refers to the amount that
+ a user has explicitly specified as an input. It is not directly a property
+ of transactions, but might be added as metadata to transactions for
+ informational purposes. How the instructed amount is interpreted
+ differs based on the "instructed amount mode" that is specified
+ together with the amount. By default, the instructed amount
+ is assumed to translate to the raw amount of the corresponding transaction.
+* "counter-party effective amount": An amount that **estimates** the effect
+ of the transaction of the balance (either wallet or bank account) of the other
+ party. This is usually a conservative estimate, i.e. when sending money,
+ this is the lower bound for the funds that the other party will obtain
+ *after* fees.
+
+
+Transaction types initialized by the wallet
+-------------------------------------------
+
+MANUAL_WITHDRAW
+ raw amount is the amount that need to be added into the exchange account,
+ this is not the same as the amount leaving the user account since their own
+ account may charge some fee that can be taken into account
+
+ ``coins`` = select-coin-for-operation(credit, mode, instructed_amount)
+
+ if instructed_amount mode = raw
+ ``raw_amount`` = instructed_amount
+
+ ``effective_amount`` = instructed_amount - coins.withdrawal_fee
+
+ if instructed_amount mode = effective
+ ``raw_amount`` = instructed_amount + coins.withdrawal_fee
+
+ ``effective_amount`` = instructed_amount
+
+DEPOSIT
+ raw amount is the amount leaving the exchange account without the wire fee,
+ this should be what the user see as an increase in the user bank account unless
+ there are some extra fee not seen from the exchange
+
+ ``coins`` = select-coin-for-operation(debit, mode, instructed_amount)
+
+ if instructed_amount mode = raw
+ ``raw_amount`` = instructed_amount
+
+ ``effective_amount`` = instructed_amount + coins.deposit_fee + coins.refresh_fee + wire.transfer_fee
+
+ if instructed_amount mode = effective
+ ``raw_amount`` = instructed_amount - coins.deposit_fee - coins.refresh_fee - wire.transfer_fee
+
+ ``effective_amount`` = instructed_amount
+
+PULL CREDIT (creating an invoice)
+ raw amount is the amount in the exchange that counter-party need will pay (purse_value),
+ this is exactly the same raw amount of the PULL DEBIT operation (paying the invoice)
+ counter-party amount is an aprox amount of the other wallet assuming the same coin selection
+ algorithm
+
+ ``coins`` = select-coin-for-operation(credit, mode, instructed_amount)
+
+ if instructed_amount mode = raw
+ ``raw_amount`` = instructed_amount
+
+ ``effective_amount`` = instructed_amount - coins.withdrawal_fee - purse_fee
+
+ if instructed_amount mode = effective
+ ``raw_amount`` = instructed_amount + coins.withdrawal_fee + purse_fee
+
+ ``effective_amount`` = instructed_amount
+
+ if instructed_amount mode = counter-party
+ ``raw_amount`` = instructed_amount - coins.counter-party_deposit_fee
+
+ ``effective_amount`` = instructed_amount - coins.counter-party_deposit_fee - coins.withdrawal_fee - purse_fee
+
+ ``counter-party_raw_amount`` = raw_amount
+
+ ``counter-party_effective_amount`` = raw_amount + coins.counter-party_deposit_fee
+
+ .. note::
+
+ counter-party_effective_amount is an estimation since refresh fee is not included.
+ Refresh fee can't be calculated because depends on the coins available in the wallet
+ of the counter-party
+
+ .. note::
+ coins.counter-party_deposit_fee is the minimum deposit_fee that can be calculated for the
+ given exchange. Counter-party may pay more if it have different preferences doing the coin
+ selection.
+
+
+PUSH DEBIT (creating a transfer)
+ raw amount is the amount in the exchange that counter-party need be able to withdraw (purse_value),
+ this is exactly the same raw amount of the PUSH CREDIT operation (getting the transfer)
+ counter-party amount is an aprox amount of the other wallet assuming the same coin selection
+ algorithm
+
+ ``coins`` = select-coin-for-operation(debit, mode, instructed_amount)
+
+ if instructed_amount mode = raw
+ ``raw_amount`` = instructed_amount
+
+ ``effective_amount`` = instructed_amount + coins.deposit_fee + purse_fee
+
+ if instructed_amount mode = effective
+ ``raw_amount`` = instructed_amount - coins.deposit_fee - purse_fee
+
+ ``effective_amount`` = instructed_amount
+
+ if instructed_amount mode = counter-party
+ ``raw_amount`` = instructed_amount + coins.counter-party_withdraw_fee
+
+ ``effective_amount`` = instructed_amount - coins.counter-party_withdraw_fee - coins.withdrawal_fee - purse_fee
+
+ ``counter-party_raw_amount`` = raw_amount
+
+ ``counter-party_effective_amount`` = raw_amount - coins.counter-party_withdraw_fee
+
+ .. note::
+ coins.counter-party_withdraw_fee is the minimum withdraw_fee that can be calculated for the
+ given exchange. Counter-party may pay more if it have different preferences doing the coin
+ selection.
+
+
+Transaction types completed by the wallet
+-------------------------------------------
+
+Next transaction types are not initiated in the wallet so instructed amount is not defined by the wallet user.
+
+We need to calculate effective_amount to check if the wallet is able to perform the operation or the user accept
+the fees.
+
+BANK_WITHDRAW
+ raw amount is that reached the bank account of the exchange,
+ this is not the same as the amount leaving the user account since their own
+ account may charge some fee that can be taken into account
+
+ ``coins`` = select-coin-for-operation(credit, mode, instructed_amount)
+
+ if instructed_amount mode = raw
+ ``raw_amount`` = instructed_amount
+
+ ``effective_amount`` = instructed_amount - coins.withdrawal_fee
+
+ if instructed_amount mode = effective
+ ``raw_amount`` = instructed_amount + coins.withdrawal_fee
+
+ ``effective_amount`` = instructed_amount
+
+
+.. note ::
+ how much wire_fee the merchant is willing to pay
+
+ ``merchant_wire_fee`` = min(wire.transfer_fee / contractTerms.amortization_factor, contractTerms.max_wire_fee)
+
+ ``merchant_deposit_fee`` = min(contractTerms.max_fee, contract_wire_fee)
+
+
+PAYMENT
+ raw amount is the amount the merchant should get if is not doing aggregated transaction.
+
+
+ ``instructed_amount`` = contractTerms.amount
+
+ ``coins`` = select-coin-for-operation(debit, mode, raw_amount)
+
+ ``raw_amount`` = instructed_amount - merchant_deposit_fee
+
+ ``effective_amount`` = instructed_amount + coins.deposit_fee + coins.refresh_fee + (wire.transfer_fee - merchant_wire_fee)
+
+ .. note::
+ The current coin-selection algorithm the order_price is neither raw_amount nor effective_amount.
+ We can calculate the raw_amount of the payment as (contractTerms.amount - max_merchant_fee) and then this
+ operation becomes equivalent than a deposit (in terms of fee calculation).
+
+
+PUSH CREDIT (getting the transfer)
+ raw amount is the purse_value in the exchange to be withdrawn
+
+ ``instructed_amount`` = p2pContract.amount
+
+ ``coins`` = select-coin-for-operation(credit, mode, raw_amount)
+
+ ``raw_amount`` = instructed_amount
+
+ ``effective_amount`` = instructed_amount - coins.withdrawal_fee
+
+ .. note::
+ In the case that the withdrawal_fee of the coin selection for the push-credit amount
+ is higher than the wire_fee of the exchange, can the wallet ask the exchange to make
+ a wire transfer of the purse instead of proceeding?
+
+PULL DEBIT (paying an invoice)
+ raw amount is the net value of the invoice without fees
+
+ ``instructed_amount`` = p2pContract.amount
+
+ ``coins`` = select-coin-for-operation(debit, mode, raw_amount)
+
+ ``raw_amount`` = instructed_amount
+
+ ``effective_amount`` = instructed_amount + coins.deposit_fee + coins.refresh_fee + wire.transfer_fee
+
+REFUND
+ raw amount is the amount that the merchant refunded
+
+ ``instructed_amount`` = refund.amount
+
+ ``raw_amount`` = instructed_amount
+
+ ``effective_amount`` = instructed_amount - refund_fee - refresh_fee
+
+ .. note::
+ There may be the case that the merchant should refund all the value of the purchase
+ and that may include paying for the refund_fee.
+
+ Is there a way that the merchant can initiate a refund of purchase + refund_fee so
+ the wallet will get the same effective_amount?
+
+Coin selection algorithm
+------------------------
+
+Is an internal optimization algorithm that will choose coins given a denomination list or current coin list
+until amount is reached. The coins selected to minimize the fee spent.
+
+``select-coin-for-operation`` will receive 3 parameters:
+
+ * operation: define if the coins are selected from wallet database or from denomination list. Possible values are:
+
+ - credit: reduce withdrawal fee, use exchange denomination list
+ - debit: reduce deposit fee, use database denomination and current coin count
+
+ * amount: how much value the coins need to sum up
+ * mode: the interpretation of the amount parameter
+
+ - net: the amount does not include the operation fee
+ - gross: the amount include the operation fee
+
+If the operation is debit and with the current coins there is no way to reach the amount then
+
+ 1. an optimized withdrawal operation can be suggested (list of denominations)
+ 2. an optimized refresh operation can be suggested (amount gap, coin to be refreshed and list of denominations to withdraw)
+
+.. note::
+
+ ``select-coin-for-operation`` must be predictable (select the same coins for the same parameters) and if
+ the difference between two amounts are the fee for a given operation:
+
+ operation: credit
+
+ withdrawal_fee = amount1 - amount2
+
+ then the wallet should select the same coins using the correct mode
+
+ select-coin(withdraw, raw, amount1) == select-coin(withdraw, effective, amount2)
+
+
+Instructed Amount Modes
+-----------------------
+
+The interpretation and possible choices of the instructed amount mode
+depends on which transaction is initiated.
+
+For withdrawal:
+
+* ``raw-mode`` (default): instructed amount is what is subtracted from the reserve balance (i.e. it's the raw amount)
+* ``effective-mode``: instructed amount is what the user wants to have as material balance in the wallet
+
+FIXME(dold): However, that does not really cover the user case where the merchant charges fees and the user has to pay for that.
+So in theory we could have a mode that withdraws enough to pay for some particular claimed order, but IMHO that's overkill.
+
+For deposits (where there is no contract that already specifies an amount):
+
+* ``max-mode``: The instructed amount is ignored (can be zero in the request), and all coins are spent (note that the calculation should be made available when the user is asked to specify an amount when using a template)
+* ``raw-mode`` (default): The instructed amount is what will be paid to the "merchant" (or the customer's bank account), ignoring wire fees
+* ``effective-mode``: The instructed amount is how the wallet's balance will be affected. Difficult to compute accurately because refresh is involved. Note that the calculation should ideally again be made available when the user is asked to specify an amount when using a template.
+
+
+For peer-push-debit:
+
+* ``raw-mode`` (default): The instructed amount is what will be paid, deposit fees are covered by the sender, withdrawal fees from the reserve by the receiver
+* ``effective-mode``: Instructed amount is the effect on the material balance. Difficult to compute accurately because refresh is involved.
+* ``counter-party-effective-mode``: Instructed amount is the effect on the counterparty's wallet balance. Difficult to compute accurately because coin selection by receiver may not match our expectations.
+
+FIXME(dold): Should we also have a mode where withdrawal fees are covered by the side that does peer-push-debit? However, that assumes the other party has the same withdrawal coin selection algorithm. FIXME(grothoff): isn't this the counterparty-effective-mode you described above, and that would seem to exactly have this issue?
+
+For peer-pull-credit:
+
+* ``raw-mode`` (default): Amount that the other party has to put in the reserve. The payer has to pay any deposit fees on top. The receiver balance is increased by the specified amount minus any withdraw fees.
+* ``effective-mode``: Amount by which the initiator's balance is increased. Difficult to compute as the receiver has to simulate different coin selections and their effect on withdraw fees to arrive at the minimum total amount that must be deposited into the reserve.
+
+
+
+Illustrative Example
+--------------------
+
+To explain the differences between raw, effective and instructed amounts, consider the following scenario: Alice wants to send money
+to Bob via a P2P push payment.
+
+Example 1:
+
+* Alice starts a withdrawal of ``KUDOS:10`` from her bank's web interface into her Taler
+ wallet. The instructed amount is ``KUDOS:10`` and (by default for bank-integrated withdrawals),
+ the mode is ``raw-mode``. After fees, ``KUDOS:9.8`` arrive in her Taler wallet.
+
+Example 3:
+
+* Alice wants to pay for a ``KUDOS:10`` monthly magazine subscription. Her Taler wallet is empty though.
+* She starts withdrawal through her Android wallet app, where she selects ``KUDOS:10`` as the instructed
+ amount with ``mode=effective-mode``. This translates to ``amountEffective=KUDOS:10`` and ``amountRaw=KUDOS:10.10``.
+* Alice is redirected to her banking app where she transfers ``KUDOS:10.10`` to the exchange.
+* Her Taler wallet balance will be ``KUDOS:10.10`` after the withdrawal completes.
+
+Note that on the amount she chooses and the fees / denom structure of the exchange, the ``amountEffective`` might be *higher*
+than the instructed amount.
+
+FIXME(dold): That flow does not work if withdrawal starts in the bank. Maybe there needs to be a mechanism
+where the wallet tells the bank the adjusted amount that needs to be transferred? That would be a new
+feature in the bank integration API.
+
+Example 4:
+
+* Alice has ``KUDOS:10`` in her wallet.
+* Alice wants to initiate a peer-push payment with ``amountInstructed=KUDOS:8``
+ and ``mode=effective-mode``. That means that after the payment, she expects
+ exactly ``KUDOS:2`` to remain in her wallet.
+* Due to the fee configuration, her wallet computes ``amountRaw=KUDOS:7.5`` and ``amountEffective=KUDOS:7.8``.
+ The effective amount in this case does **not** equal the instructed amount, despite the ``mode=effective-mode``.
+ That's because there no amount that can be spend so that the spend amount with resulting refresh
+ fees equal ``KUDOS:8``.
+* Alice confirms the peer-push payment initiation, and exactly ``KUDOS:7.5`` are credited
+ to the purse that her wallet creates.
+* Bob merges the purse into his reserve. Bob's wallet automatically withdraws
+ from the reserve, and his wallet balance increases by ``KUDOS:7.1``, since
+ withdrawal fees are deducted.
+
+Balances
+--------
+
+The following types of balances are defined:
+
+- ``available``: Balance that the wallet believes will certainly be available
+ for spending, modulo any failures of the exchange or double spending issues.
+ This includes available coins *not* allocated to any
+ spending/refresh/... operation. Pending withdrawals are *not* counted
+ towards this balance, because they are not certain to succeed.
+ Pending refreshes *are* counted towards this balance.
+ This balance type is nice to show to the user, because it does not
+ temporarily decrease after payment when we are waiting for refreshes
+
+- ``material``: Balance that the wallet believes it could spend *right now*,
+ without waiting for any operations to complete.
+ This balance type is important when showing "insufficient balance" error messages.
+
+- ``age-acceptable``: Subset of the material balance that can be spent
+ with age restrictions applied.
+
+- ``merchant-acceptable``: Subset of the material balance that can be spent with a particular
+ merchant (restricted via min age, exchange, auditor, wire_method).
+
+- ``merchant-depositable``: Subset of the merchant-acceptable balance that the merchant
+ can accept via their supported wire methods.
+
+Balance Mismatch
+----------------
+
+The wallet uses the following terminology when an operation can't succeed
+because the balance is too low, even though the instructed amount
+
+- "fee-gap-estimate": Additional (material) balance that the wallet estimates it
+ still needs for the operation to succeed.
+
+ - This value is an estimated, because newly withdrawn coins might have different fees.
+ - This value is specified *per exchange*, because each exchange has different fees.
+
+FIXME(dold): Should we specify an upper-bound fee-gap-estimate to simplify it for the UIs?
+
+
+Discussion / Q&A
+================
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/042-synthetic-wallet-errors.rst b/design-documents/042-synthetic-wallet-errors.rst
new file mode 100644
index 00000000..97262002
--- /dev/null
+++ b/design-documents/042-synthetic-wallet-errors.rst
@@ -0,0 +1,57 @@
+DD 42: Wallet Dev Experiments
+#############################
+
+Summary
+=======
+
+This design document defines new ``taler://`` URIs to cause synthetic errors
+or special states in the wallet that can then be rendered by the UI.
+
+Motivation
+==========
+
+UIs need to handle various (error-) states and responses of wallet-core. It's
+not easy to cover all of these states and responses manually. Some of them are
+hard to reach or simulate without an elaborate test setup.
+
+Requirements
+============
+
+The implementation of synthetic errors should be as separate from production
+code as possible, to avoid making the normal code paths unreadable.
+
+
+Proposed Solution
+=================
+
+Special taler:// URIs
+---------------------
+
+* ``taler://dev-experiment/$STATE_ID``
+* ``taler://pay/...?dev-experiment=``
+
+Special http(s):// URIs
+-----------------------
+
+* ``http(s)://*.dev-experiment.taler.net/``
+
+ * URLs for this subdomain are handled specially by the
+ wallet's HTTP layer and return fixed / mocked responses
+ instead of making real requests.
+
+
+List of experiments
+-------------------
+
+
+
+Alternatives
+============
+
+Drawbacks
+=========
+
+Discussion / Q&A
+================
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/043-managing-prebuilt-artifacts.rst b/design-documents/043-managing-prebuilt-artifacts.rst
new file mode 100644
index 00000000..3d0debc8
--- /dev/null
+++ b/design-documents/043-managing-prebuilt-artifacts.rst
@@ -0,0 +1,107 @@
+DD 43: Managing Prebuilt Artifacts and Source-Level Dependencies
+################################################################
+
+Summary
+=======
+
+This design document defines how the GNU Taler project manages prebuilt
+artifacts and other source-level dependencies in repositories
+that are part of project.
+
+Motivation
+==========
+
+Some repositories have source-level dependencies on the build results of other
+repositories. While it is possible to build these dependencies from scratch,
+we often want to avoid that extra step in order to make building the software
+easier and faster.
+
+Examples are:
+
+* man-pages built via Sphinx, produced in ``docs.git`` and consumed in ``exchange.git``.
+* SPAs used by the exchange, merchant libeufin.
+* (formerly): The ``taler-wallet-core-embedded.js`` file used
+ by the Android repo.
+
+Another type of source-level dependency is on other **source** files.
+Examples for this are:
+
+* The ``build-common.git`` repository that contains common build-time helpers
+* The ``gana.git`` repository
+
+Requirements
+============
+
+* We are a free software project, users must always be able to
+ easily re-build the prebuilt artifacts for themselves.
+* We want to reduce reliance on third party infrastructure as much
+ as possible.
+* We want to keep our own infrastructure as slim as possible.
+* Builds must be reproducible and remain reproducible in the future.
+* Offline builds should be supported as well as possible.
+* Ideally, prebuilt artifacts can easily be cached / archived by third parties.
+
+Proposed Solution
+=================
+
+Instead of using a full-blown artifact management solution from the start, we
+make use of Git. Since Git is not very good at managing binary artifacts,
+prebuilt files are not managed alongside the source code. Instead, we use
+(orphan-)branches) in a (possibly separate) repository to manage them. This
+allows us to re-use Git authentication and Git commit signing.
+
+Due to a historical accident, prebuilt files are currently stored in the
+``prebuilt`` branch of the ``wallet-core.git`` repository. This might change
+in the future.
+
+To enable forwards-compatibility, we are implementing the following approach:
+The ``taler.net`` HTTP server redirects requests in the form of
+``https://artifacts.taler.net/$component/$version/$file`` to
+``https://git.taler.net/$repo.git/tree/$version/$file?h=$branch``, where
+``$component`` determines ``$repo`` and ``$branch``.
+
+We are also introducing the new rule that a prebuilt artifact must be a single
+archive file (preferable ``.tar.gz.``).
+
+Repositories that produce artifacts *MUST* have phony Makefile helper targets
+to (a) create the prebuilt artifact (b) check out the prebuilt branch as a Git worktree, (c)
+move the artifact to the right place in the prebuilt branch and commit/push.
+
+Repositories that depend on prebuilt components must download them
+in their ``./bootstrap`` script. After downloading, the bootstrap
+script *SHOULD* verify a checksum of the downloaded artifact.
+
+FIXME: Link to an example bootstrap file, once the approach from this document
+is fully implemented.
+
+Alternatives
+============
+
+* The prebuilt branch could be integrated into source repositories that
+ depend on it via a git submodule. This has the following disadvantages:
+
+ 1. Git submodules are difficult to handle for some developers. We've had issues
+ in the past where the prebuilt submodule wasn't integrated properly and would
+ lead to non-reproducible builds
+ 2. Relying purely on the Git commit hash of the prebuilt branch
+ makes it very difficult to know which version of the prebuilt
+ artifact is being used. It also makes it very difficult
+ to reliable find older versions of the artifact.
+ 3. Relying on the commit hash instead of a version and artifact hash
+ couples the artifact to the Git commit. That means that
+ we can never compact the commit history of the prebuilt
+ branch of move artifacts around.
+
+* Set up a full-blown artifact management solution like JFrog Artifactory.
+ That's costly and requires a lot of admin work.
+
+* Never rely on prebuilt files. That slows down the build process
+ and in some cases requires exotic dependencies.
+
+Drawbacks
+=========
+
+Discussion / Q&A
+================
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/044-ci-system.rst b/design-documents/044-ci-system.rst
new file mode 100644
index 00000000..e38632c0
--- /dev/null
+++ b/design-documents/044-ci-system.rst
@@ -0,0 +1,130 @@
+DD 44: CI System
+################
+
+Summary
+=======
+
+This documents describes Taler's CI system based on Buildbot.
+
+This document uses `RFC 2119 <https://tools.ietf.org/html/rfc2119>`_
+keywords throughout.
+
+Motivation
+==========
+
+With the current CI system there are an array of issues:
+
+- Central place for all the jobs.
+- The central config is poorly organized.
+- We should prefer to keep as much CI logic in respective project source repos
+ as possible.
+- Jobs should be split up further to allow for more granular control and
+ insight.
+- Job triggers are unclear.
+- The build environments are mutable.
+- Non-trivial and error-prone to keep track of environment state.
+- Hard to get an overview of what repo is causing a failure, at a quick glance.
+- Bad for development workflow on a single project when you are getting
+ false-negatives all the time.
+
+Proposed Solution
+=================
+
+General
+-------
+
+Jobs shall be executed inside of containers.
+
+One build pipeline (aka. "builder") per repo.
+
+Build steps are generated from directory structure within a given repo.
+
+Example directory structure:
+
+::
+
+ contrib
+ └── ci
+ ├── ci.sh
+ ├── Containerfile
+ └── jobs
+ ├── 0-codespell
+ │   ├── config.ini
+ │   ├── dictionary.txt
+ │   └── job.sh
+ ├── 1-build
+ │   ├── build.sh
+ │   └── job.sh
+ └── 2-docs
+ ├── docs.sh
+ └── job.sh
+
+Job directories **MUST** follow this pattern:
+``<repo_root>/contrib/ci/jobs/<n-job_name>/``
+
+``n`` is an integer used for ordering the build steps.
+
+Job directories **MUST** contain a script named ``job.sh`` which **MAY**
+execute other scripts.
+
+Config files may optionally be created, and MUST be named ``config.ini`` and
+placed in the job directory.
+
+Available config options:
+
+::
+
+ [build]
+ HALT_ON_FAILURE = True|False
+ WARN_ON_FAILURE = True|False
+ CONTAINER_BUILD = True|False
+ CONTAINER_NAME = <string>
+ CONTAINER_ARCH = <string>
+
+
+Unless *all* jobs specify a "CONTAINER_NAME" in their custom config a
+container file **MUST** be present at ``<repo_root>/contrib/ci/Containerfile``.
+The container file will be built and used to run all of a repo's jobs
+by default.
+
+All projects SHOULD have a ``build`` step and a ``test`` step, at a minimum.
+
+Running CI Locally
+------------------
+
+Running the CI scripts locally can be useful for development and testing.
+
+Included in each CI directory is a script which simplifies running jobs
+in the same way the CI Worker does, in containers, using ``podman``.
+
+::
+
+ # Usage:
+ ./contrib/ci/ci.sh <job-name>
+
+ # For example, if the CI jobs tree looks like this:
+ ./contrib/ci/jobs
+ ├── 0-codespell/
+ ├── 1-build/
+ ├── 2-test/
+ ├── 3-docs/
+ ├── 4-deb-package/
+ └── 5-deploy-package/
+
+ # Then you can run job '0-codespell' as follows:
+ ./contrib/ci/ci.sh 0-codespell
+
+ # If you are using podman and have "qemu-user-binfmt" installed
+ # then you may attempt to run any job under an alternative CPU
+ # architecture by providing a second argument.
+ # For example:
+ ./contrib/ci/ci.sh 0-codespell arm64
+
+
+Additional Builders
+-------------------
+
+To run some tests there is a need for many or most project's sourcecode to be
+available in the same environment. This will be a separate builder/pipeline
+from the per-repo builders. Triggers for this builder are yet to be
+determined.
diff --git a/design-documents/045-kyc-inheritance.rst b/design-documents/045-kyc-inheritance.rst
new file mode 100644
index 00000000..f33e7ee3
--- /dev/null
+++ b/design-documents/045-kyc-inheritance.rst
@@ -0,0 +1,186 @@
+DD 45: Single-Depth Inheritance of KYC for Reserves
+###################################################
+
+Summary
+=======
+
+This document presents and discusses a mechanism by which a reserve A can
+provide KYC attestation for another reserve B, whenever A's KYC attestation is
+the result of a proper KYC-process and not inherited itself. During the
+transitive attestation process, A can change the birthday for reserve B become
+younger, i.e. choose a date closer to the current date than the original
+birthday.
+
+
+Motivation
+==========
+
+There are two reasons that motivate our proposal:
+
+#. KYC attestation of a reserve is a must for Peer-2-Peer payments. However,
+ a KYC process is usually costly for the exchange and -ultimately- the
+ customer. When a customer has multiple long-term reserves, it should be
+ possible to inherit the KYC attestation from one to another.
+
+#. A parent should be able to provide KYC attestation for the long-term reserve
+ of his or her child and at the same time provide appropriate birthday
+ information. That way, the child can withdraw money from its reserve
+
+ - with appropriate and evolving age-restriction always in place,
+
+ - no further age-commitment interaction with the parent.
+
+With the ability to attest KYC transitively, we can reduce the cost of
+ownership of long-term reserves and enable the principle of subsidiarity,
+according to which parents are responsible for age-restriction settings.
+
+
+Requirements
+============
+
+* none
+
+Proposed Solution
+=================
+
+There are changes in the exchange and in the wallet necessary.
+
+Changes in the Exchange
+^^^^^^^^^^^^^^^^^^^^^^^
+
+A new configuration option in the TALER-configuration defines the maximum
+number of attestations that a (KYC'ed) reserve can provide for other reserves.
+
+.. code:: none
+
+ [kyc-legitimization-inheritance]
+ MAXIMUM_ATTESTATIONS = [number]
+
+
+The database schema needs to be adjusted to incorporate
+
+* a boolean field ``inherited`` in the table ``kyc_attributes`` to indicate the
+ inheritance status
+
+* an integer field ``attestations`` in the table ``reserves`` to count the
+ number of transitive attestations performed by a reserve.
+
+
+On the exchange we propose the following new endpoint:
+
+
+.. http:post:: /kyc-attest/$TARGET_RESERVE_PUB
+
+**Request:**
+
+The request body must be a `KYCAttestationRequest` object.
+
+**Response:**
+
+ :http:statuscode:`200 OK`:
+ Both, the attesting and the target reserves were known to the exchange, and the
+ KYC data of the attesting reserve has been successfully inherited by the
+ target reserve (with optionally adjusted birthday).
+ :http:statuscode:`403 Forbidden`:
+ The attesting reserve is not allowed to transitively attest another reserve.
+ This is because the attesting reserve either
+
+ #. lacks KYC attestation or
+
+ #. its KYC attestation was itself inherited or
+
+ #. has reached the allowed maximum number of transitive attestations.
+
+ The response comes with a standard `ErrorDetail`.
+ :http:statuscode:`404 Not found`:
+ One of the reserve keys belongs to a reserve which is unknown to the exchange.
+ The response comes with a standard `ErrorDetail`, containing the unknown key.
+ :http:statuscode:`409 Conflict`:
+ The birthday in the request is not acceptable, as it points to an earlier
+ point in time (more distant from current time) than the birthday of the
+ attesting reserve.
+
+**Details:**
+
+.. ts:def:: KYCAttestationRequest
+
+ interface KYCAttestationRequest {
+ // An optional birthday for the target reserve. MUST be equal or younger
+ // (more recent to current time) than the birthday of the attesting
+ // reserve.
+ birthday?: FuzzyDateString;
+
+ // The public key of the attesting reserve
+ attester_pub: EddsaPublicKey;
+
+ // Signature of purpose
+ // ``TALER_SIGNATURE_WALLET_RESERVE_TRANSITIVE_KYC`` over
+ // a `TALER_ReserveKYCAttestationPS`.
+ attester_sig: EddsaSignature;
+ }
+
+
+.. ts:def:: FuzzyDateString
+
+ // A date of the form "YYYY-MM-DD","YYYY-MM-00" or "YYYY-00-00".
+ // "YYYY-MM-00" will be evaluated as "YYYY-MM-01" and
+ // "YYYY-00-00" will be evaluated as "YYYY-01-01".
+ type FuzzyDateString = string;
+
+
+.. _TALER_ReserveKYCAttestationPS:
+.. sourcecode:: c
+
+ struct TALER_ReserveKYCAttestationPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_WALLET_RESERVE_TRANSITIVE_KYC
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct TALER_ReservePublicKeyP attester_reserve_pub;
+ struct TALER_ReservePublicKeyP target_reserve_pub;
+ /* If no birthday is set, must be all 0 */
+ char birthday[sizeof("YYYY-MM-DD")];
+ }
+
+
+Changes in the Wallet
+^^^^^^^^^^^^^^^^^^^^^
+
+We need a workflow for the attestation of one wallet through another.
+
+TODO.
+
+
+Definition of Done
+==================
+
+For the exchange, the implementation of the configuration option and the
+endpoint, and corresponding unit tests in ``src/testing`` are necessary.
+
+
+For the wallet: TODO.
+
+Alternatives
+============
+
+* KYC for a reserve can only be provided by a full KYC legitimization process.
+
+Drawbacks
+=========
+
+Other than adding code to the exchange: unknown.
+
+Discussion / Q&A
+================
+
+The proposed solution makes the principle of subsidiarity for age-restrictions
+(i.e parents are responsible for setting the age-restriction) explicit in the
+code.
+
+It also simplifies the KYC process for many situations for customers: Families
+members and partners benefit from it.
+
+However, the proposed solution still allows for other ways to set
+age-restriction in the wallet. For example, parents who do **not** have a
+Taler wallet, are still able to assist their children with the settings of
+age-restriction during the withdraw process.
diff --git a/design-documents/046-mumimo-contracts.rst b/design-documents/046-mumimo-contracts.rst
new file mode 100644
index 00000000..8cb35316
--- /dev/null
+++ b/design-documents/046-mumimo-contracts.rst
@@ -0,0 +1,709 @@
+DD 46: Contract Format v1
+#########################
+
+Summary
+=======
+
+The contract v1 format enables a multitude of advanced interactions between
+merchants and wallets, including donations, subscriptions, coupons, currency
+exchange and more.
+
+Motivation
+==========
+
+The existing v0 contract format is too simplistic to
+support many frequenly requested types of contracts.
+
+Requirements
+============
+
+We want Taler to support various interesting use-cases:
+
+ - Unlinkable, uncopyable subscriptions without accounts (reader can pay with
+ Taler to subscribe to online publication, read unlimited number of
+ articles during a certain period, transfer subscription to other devices,
+ maintain unlinkability / full anonymity amongst all anonymous
+ subscribers).
+
+ - Coupons, discounts and stamps -- like receiving a discount on a product,
+ product basket or subscription -- based on previous purchase(s). Again,
+ with unlinkability and anonymity (modulo there being other users eligible
+ for the discount).
+
+ - Subscription tokens lost (due to loss of device without backup) should
+ be recoverable from any previous backup of the subscription.
+
+ - Currency conversion, that is exchanging one currency for another.
+
+ - Donations, including privacy-preserving tax receipts that prove that the
+ user donated to an entity that is eligible for tax-deductions but without
+ revealing which entity the user donated to. At the same time, the entity
+ issuing the tax receipt must be transparent (to the state) with respect to
+ the amount of tax-deductable donations it has received.
+
+ - Throttled political donations where each individual is only allowed to
+ donate anonymously up to a certain amount per year or election cycle.
+
+ - Unlinkable gifts -- enabling the purchase of digital goods (such as
+ articles, albums, etc.) to be consumed by a third party. For example, a
+ newspaper subscription may include a fixed number of articles that can be
+ gifted to others each week, all while maintaining unlinkability and
+ anonymity between the giver and the recipient.
+
+ - Temporally-constrained, unlinkable event ticketing. Allowing visitors to
+ use Taler to purchase a ticket for an event. This ticket grants entry and
+ exit privileges to the event location during a specified time window, while
+ preserving the anonymity of the ticket holder (within the group of all the
+ ticket holders).
+
+ - Event deposit systems. A deposit mechanism for events where customers
+ receive a token alongside their cup or plate, which they are expected to
+ return. This system validates that the cup or plate was legitimately
+ acquired (i.e., not brought from home or stolen from a stack of dirty items)
+ and incentivizes return after use.
+
+
+Proposed Solution
+=================
+
+Merchants will also blindly sign tokens (not coins) to indicate the
+eligibility of a user for certain special offers. Contracts will be modified
+to allow requiring multiple inputs (to be *provisioned* to the merchant) and
+multiple outputs (to be *yielded* by the merchant). The wallet will then allow
+the user to select between the choices that the user could pay for, or possibly
+make an automatic choice if the correct choice is obvious. One output option is
+blindly signed coins from another exchange, possibly in a different currency.
+Another output option is blindly signed donation receipts from a DONation
+AUthority (DONAU). Subscriptions can be modeled by requiring the wallet to
+provision a token of the same type that is also yielded by the contract. For
+security, payments using subscription tokens (and possibly certain other special
+tokens?) will be limited to a list of domains explicitly defined as trusted by
+the token issuer. When paying for a contract, the wallet must additionally sign
+over the selected sub-contract index and a hash committing it to the blinded
+envelopes (if any). The merchant backend will (probably?) need to be changed
+to truly support multiple currencies (ugh).
+
+.. _contract-terms-v1:
+
+New Contract Terms Format
+-------------------------
+
+The contract terms v1 will have the following structure:
+
+.. ts:def:: ContractTermsV1
+
+ interface ContractTermsV1 {
+
+ // This is version 1, the previous contract terms SHOULD
+ // be indicated using "0", but in v0 specifying the version
+ // is optional.
+ version: "1";
+
+ // Unique, free-form identifier for the proposal.
+ // Must be unique within a merchant instance.
+ // For merchants that do not store proposals in their DB
+ // before the customer paid for them, the ``order_id`` can be used
+ // by the frontend to restore a proposal from the information
+ // encoded in it (such as a short product identifier and timestamp).
+ order_id: string;
+
+ // Price to be paid for the transaction. Could be 0.
+ // The price is in addition to other instruments,
+ // such as rations and tokens.
+ // The exchange will subtract deposit fees from that amount
+ // before transferring it to the merchant.
+ price: Amount;
+
+ // URL where the same contract could be ordered again (if
+ // available). Returned also at the public order endpoint
+ // for people other than the actual buyer (hence public,
+ // in case order IDs are guessable).
+ public_reorder_url?: string;
+
+ // Time when this contract was generated.
+ timestamp: Timestamp;
+
+ // After this deadline, the merchant won't accept payments for the contract.
+ pay_deadline: Timestamp;
+
+ // Transfer deadline for the exchange. Must be in the
+ // deposit permissions of coins used to pay for this order.
+ wire_transfer_deadline: Timestamp;
+
+ // Merchant's public key used to sign this proposal; this information
+ // is typically added by the backend. Note that this can be an ephemeral key.
+ merchant_pub: EddsaPublicKey;
+
+ // Base URL of the (public!) merchant backend API.
+ // Must be an absolute URL that ends with a slash.
+ merchant_base_url: string;
+
+ // More info about the merchant (same as in v0).
+ merchant: Merchant;
+
+ // Human-readable description of the contract.
+ summary: string;
+
+ // Map from IETF BCP 47 language tags to localized summaries.
+ summary_i18n?: { [lang_tag: string]: string };
+
+ // URL that will show that the order was successful after
+ // it has been paid for. Optional. When POSTing to the
+ // merchant, the placeholder "${ORDER_ID}" will be
+ // replaced with the actual order ID (useful if the
+ // order ID is generated server-side and needs to be
+ // in the URL).
+ // Note that this placeholder can only be used once.
+ // Either fulfillment_url or fulfillment_message must be specified.
+ fulfillment_url?: string;
+
+ // Message shown to the customer after paying for the order.
+ // Either fulfillment_url or fulfillment_message must be specified.
+ fulfillment_message?: string;
+
+ // Map from IETF BCP 47 language tags to localized fulfillment
+ // messages.
+ fulfillment_message_i18n?: { [lang_tag: string]: string };
+
+ // List of products that are part of the purchase (see `Product`).
+ products: Product[];
+
+ // After this deadline has passed, no refunds will be accepted.
+ refund_deadline: Timestamp;
+
+ // Specifies for how long the wallet should try to get an
+ // automatic refund for the purchase. If this field is
+ // present, the wallet should wait for a few seconds after
+ // the purchase and then automatically attempt to obtain
+ // a refund. The wallet should probe until "delay"
+ // after the payment was successful (i.e. via long polling
+ // or via explicit requests with exponential back-off).
+ //
+ // In particular, if the wallet is offline
+ // at that time, it MUST repeat the request until it gets
+ // one response from the merchant after the delay has expired.
+ // If the refund is granted, the wallet MUST automatically
+ // recover the payment. This is used in case a merchant
+ // knows that it might be unable to satisfy the contract and
+ // desires for the wallet to attempt to get the refund without any
+ // customer interaction. Note that it is NOT an error if the
+ // merchant does not grant a refund.
+ auto_refund?: RelativeTime;
+
+ // Delivery location for (all!) products (same as in v0).
+ delivery_location?: Location;
+
+ // Time indicating when the order should be delivered.
+ // May be overwritten by individual products.
+ delivery_date?: Timestamp;
+
+ // Nonce generated by the wallet and echoed by the merchant
+ // in this field when the proposal is generated.
+ // Note: required in contract, absent in order!
+ nonce: string;
+
+ // Array of possible specific contracts the wallet/customer
+ // may choose from by selecting the respective index when
+ // signing the deposit confirmation.
+ choices: ContractChoice[];
+
+ // Map from token family slugs to meta data about the
+ // respective token family.
+ token_families: { [token_family_slug: string]: TokenFamily };
+
+ // Extra data that is only interpreted by the merchant frontend.
+ // Useful when the merchant needs to store extra information on a
+ // contract without storing it separately in their database.
+ extra?: any;
+
+ // Maximum total deposit fee accepted by the merchant for this contract.
+ max_fee: Amount;
+
+ // Exchanges that the merchant accepts for this currency.
+ exchanges: Exchange[];
+
+ }
+
+.. ts:def:: ContractChoice
+
+ interface ContractChoice {
+
+ // List of inputs the wallet must provision (all of them) to
+ // satisfy the conditions for the contract.
+ inputs: ContractInput[];
+
+ // List of outputs the merchant promises to yield (all of them)
+ // once the contract is paid.
+ outputs: ContractOutput[];
+
+ }
+
+.. ts:def:: ContractInput
+
+ type ContractInput =
+ | ContractInputRation
+ | ContractInputToken;
+
+.. ts:def:: ContractInputRation
+
+ interface ContractInputRation {
+
+ type: "coin";
+
+ // Price to be paid for the transaction.
+ price: Amount;
+
+ // FIXME-DOLD: do we want to move this into a 'details'
+ // sub-structure as done with tokens below?
+ class: "ration";
+
+ // Base URL of the ration authority.
+ ration_authority_url: string;
+
+ };
+
+.. ts:def:: ContractInputToken
+
+ interface ContractInputToken {
+
+ type: "token";
+
+ // Slug of the token family in the
+ // 'token_families' map on the top-level.
+ token_family_slug: string;
+
+ // Number of tokens of this type required.
+ // Defaults to one if the field is not provided.
+ number?: Integer;
+
+ };
+
+.. ts:def:: ContractOutput
+
+ type ContractOutput =
+ | ContractOutputCoin
+ | ContractOutputTaxReceipt
+ | ContractOutputToken;
+
+.. ts:def:: ContractOutputCoin
+
+ interface ContractOutputCoin {
+
+ type: "coins";
+
+ // Amount of coins that will be yielded.
+ // This excludes any applicable withdraw fees.
+ brutto_yield: Amount;
+
+ // Base URL of the exchange that will issue the
+ // coins.
+ exchange_url: string;
+
+ };
+
+.. ts:def:: ContractOutputTaxReceipt
+
+ interface ContractOutputTaxReceipt {
+
+ type: "tax-receipt";
+
+ // Base URL of the donation authority that will
+ // issue the tax receipt.
+ donau_url: string;
+
+ };
+
+.. ts:def:: ContractOutputToken
+
+ interface ContractOutputToken {
+
+ type: "token";
+
+ // Slug of the token family in the
+ // 'token_families' map on the top-level.
+ token_family_slug: string;
+
+ // Start of the validity period of the token.
+ valid_after: Timestamp;
+
+ // Number of tokens to be yelded.
+ // Defaults to one if the field is not provided.
+ number?: Integer;
+
+ }
+
+.. ts:def:: TokenClass
+
+ type TokenClass =
+ | TokenClassSubscription
+ | TokenClassDiscount
+
+.. ts:def:: TokenClassSubscription
+
+ interface TokenClassSubscription {
+
+ class: "subscription";
+
+ // Array of domain names where this subscription
+ // can be safely used (e.g. the issuer warrants that
+ // these sites will re-issue tokens of this type
+ // if the respective contract says so). May contain
+ // "*" for any domain or subdomain.
+ trusted_domains: string[];
+
+ };
+
+.. ts:def:: TokenClassDiscount
+
+ interface TokenClassDiscount {
+
+ class: "discount";
+
+ // Array of domain names where this discount token
+ // is intended to be used. May contain "*" for any
+ // domain or subdomain. Users should be warned about
+ // sites proposing to consume discount tokens of this
+ // type that are not in this list that the merchant
+ // is accepting a coupon from a competitor and thus
+ // may be attaching different semantics (like get 20%
+ // discount for my competitors 30% discount token).
+ expected_domains: string[];
+
+ };
+
+
+.. ts:def:: TokenFamily
+
+ interface TokenFamily {
+
+ // Human-readable name of the token family.
+ name: string;
+
+ // Human-readable description of the semantics of
+ // this token family (for display).
+ description: string;
+
+ // Map from IETF BCP 47 language tags to localized descriptions.
+ description_i18n?: { [lang_tag: string]: string };
+
+ // Public keys used to validate tokens issued by this token family.
+ keys: TokenSignerPublicKeyGroup;
+
+ // Class-specific information of the token
+ details: TokenClass;
+
+ // Must a wallet understand this token type to
+ // process contracts that consume or yield it?
+ critical: boolean;
+
+ // Number of tokens issued according to ASS authority
+ // FIXME: this is still rather speculative in the design...
+ ass?: Integer;
+
+ // Signature affirming sum of token issuance deposit (?) fees
+ // collected by an exchange according to the ASS authority.
+ // FIXME: this is still rather speculative in the design...
+ ass_cost?: Amount;
+
+ // Signature affirming the ass by the ASS authority.
+ // FIXME: this is still rather speculative in the design...
+ ass_sig?: EddsaSignature;
+
+ };
+
+
+.. ts:def:: TokenSignerPublicKeyGroup
+
+ type TokenSignerPublicKeyGroup =
+ | TokenSignerPublicKeyGroupRsa
+ | TokenSignerPublicKeyGroupCs;
+
+.. ts:def:: TokenSignerPublicKeyGroupRsa
+
+ interface TokenSignerPublicKeyGroupRsa {
+ cipher: "RSA";
+
+ public_keys: {
+ // RSA public key.
+ rsa_pub: RsaPublicKey;
+
+ // Start time of this key's validity period.
+ valid_after?: Timestamp;
+
+ // End time of this key's validity period.
+ valid_before: Timestamp;
+ }[];
+ }
+
+.. ts:def:: TokenSignerPublicKeyGroupCs
+
+ interface TokenSignerPublicKeyGroupCs {
+ cipher: "CS";
+
+ public_keys: {
+ // CS public key.
+ cs_pub: Cs25519Point;
+
+ // Start time of this key's validity period.
+ valid_after?: Timestamp;
+
+ // End time of this key's validity period.
+ valid_before: Timestamp;
+ }[];
+ }
+
+
+Alternative Contracts
+---------------------
+
+The contract terms object may contain any number of alternative contracts that
+the user must choose between. The alternatives can differ by inputs, outputs
+or other details. The wallet must filter the contracts by those that the user
+can actually pay for, and move those that the user could currently not pay for
+to the end of the rendered list. Similarly, the wallet must move up the
+cheaper contracts, so if a contract has a definitively lower price and
+consumes an available discount token, that contract should be moved up in the
+list.
+
+Which specific alternative contract was chosen by the user is indicated in the
+``choice_index`` field of the :ref:`TALER_DepositRequestPS <taler_depositrequestps>`.
+
+
+Output Commitments
+------------------
+
+When a contract has outputs, the wallet must send an array of blinded tokens,
+coins or tax receipts together with the payment request. The order in the
+array must match the order in the outputs field of the contract. For currency
+outputs, one array element must include all of the required planchets for a
+batch withdrawal, but of course not the reserve signature.
+
+ .. note::
+
+ We can probably spec this rather nicely if we first change the
+ batch-withdraw API to only use a single reserve signature.
+
+This array of blinded values is hashed to create the output commitment hash
+(``h_outputs``) in the :ref:`TALER_DepositRequestPS <taler_depositrequestps>`.
+
+
+
+Subscriptions
+-------------
+
+The user buys a subscription (and possibly at the same time an article) using
+currency and the contract yields an additional subscription token as an
+output. Active subscriptions are listed below the currencies in the wallet
+under a new heading. Subscriptions are never auto-renewing, if the user wants
+to extend the subscription they can trivially pay for it with one click.
+
+When a contract consumes and yields exactly one subscription
+token of the same type in a trusted domain, the wallet may automatically
+approve the transaction without asking the user for confirmation (as it is free).
+
+The token expiration for a subscription can be past the "end date" to enable a
+previous subscription to be used to get a discount on renewing the
+subscription. The wallet should show applicable contracts with a lower price
+that only additionally consume subscription tokens after their end date before
+higher-priced alternative offers.
+
+Subscription tokens are "critical" in that a wallet implementation must
+understand them before allowing a user to interact with this class of token.
+Subscription token secrets should be derived from a master secret associated
+with the subscription, so that the private keys are recoverable from backup.
+To obtain the blind signatures, a merchant must offer an endpoint where
+one can submit the public key of the N-1 subscription token and obtain the
+blinded signature over the N-th subscription token. The wallet can then
+effectively recover the subscription from backup using a binary search.
+
+The merchant SPA should allow the administrator to create (maybe update) and
+delete subscriptions. Each subscription is identified by a subscription
+label and includes a validity period.
+
+The merchant backend must then automatically manage (create, use, delete) the
+respective signing keys. When creating an order, the frontend can just refer
+to the subscription label (and possibly a start date) in the inputs or
+outputs. The backend should then automatically substitute this with the
+respective cryptographic fields for the respective time period and
+subscription label.
+
+
+
+
+Discounts
+---------
+
+To offer a discount based on one or more previous purchases, a merchant must
+yield some discount-specific token as an output with the previous purchase,
+and then offer an alternative contract with a lower price that consumes currency
+and the discount token. The wallet should show contracts with a lower price that
+only additionally consume discount tokens
+
+The merchant SPA should allow the administrator to create (maybe update) and
+delete discount tokens. Each discount token is identified by a discount
+label and includes an expiration time or validity duration.
+
+The merchant backend must then automatically manage (create, use, delete) the
+respective signing keys. When creating an order, the frontend can just refer
+to the discount token label in the inputs or outputs. The backend should then
+automatically substitute this with the respective cryptographic fields for the
+respective discount token.
+
+
+Donation Authority
+------------------
+
+A donation authority (DONAU) implements a service that is expected to be run
+by a government authority that determines eligibility for tax deduction. A
+DONAU blindly signs tax receipts using a protocol very close to that of the
+Taler exchange's withdraw protocol, except that the reserves are not filled
+via wire transfers but instead represent accounts of the organizations
+eligible to issue tax deduction receipts. These accounts are bascially
+expected to have only negative balances, but the DONAU may have a
+per-organization negative balance limit to cap tax deduction receipt
+generation to a plausible account. DONAU administators are expected to be
+able to add, update or remove these accounts using a SPA. Tax receipts
+are blindly signed by keys that always have a usage period of one calendar
+year.
+
+A stand-alone app for tax authorities can scan QR codes representing DONAU
+signatures to validate that a given tax payer has donated a certain amount.
+As RSA signatures are typically very large and a single donation may require
+multiple blind signatures, CS blind signatures must also be supported. To
+avoid encoding the public keys, QR codes with tax receipts should reference
+the DONAU, the year and the amount, but not the specific public key. A
+single donation may nevertheless be rendered using multiple QR codes.
+
+Revocations, refresh, deposits, age-restrictions and other exchange features
+are not applicable for a DONAU.
+
+The merchant SPA should allow the administrator to manage DONAU accounts in
+the merchant backend. Each DONAU account includes a base URL and a private
+signing key for signing the requests to the DONAU on behalf of the eligible
+organization.
+
+When creating an order, the frontend must specify a configured DONAU base URL
+in the outputs. The backend should then automatically interact with the DONAU
+when the wallet supplies the payment request with the blinded tax receipts.
+The DONAU interaction must only happen after the exchange confirmed that the
+contract was successfully paid. A partial error must be returned if the
+exchange interaction was successful but the DONAU interaction failed. In this
+case, the fulfillment action should still be triggered, but the wallet should
+display a warning that the donation receipt could not be obtained. The wallet
+should then re-try the payment (in the background with an exponential
+back-off) to possibly obtain the tax receipt at a later time.
+
+
+Tax Receipts
+------------
+
+Tax receipts differ from coins and tokens in that what is blindly signed over
+should be the taxpayer identification number of the tax payer. The format of
+the taxpayer identification number should simply be a string, with the rest
+being defined by the national authority. The DONAU should indicate in its
+``/config`` response what format this string should have, using possibly both
+an Anastasis-style regex and an Anastasis-style function name (to check things
+like checksums that cannot be validated using a regex). Wallets must then
+validate the regex (if given) and if possible should implement the
+Anastasis-style logic.
+
+Wallets should collect tax receipts by year and offer an
+export functionality. The export should generate either
+
+ (a) a JSON file,
+ (b) a PDF (with QR codes), or
+ (c) a series of screens with QR codes.
+
+Wallets may only implement some of the above options due to resource
+constraints.
+
+The documents should encode the taxpayer ID, the amount and the DONAU
+signature (including the year, excluding the exact public key as there should
+only be one possible).
+
+
+Rationing (future work)
+-----------------------
+
+If per-capita rationing must be imposed on certain transactions, a rationing
+authority (RA) must exist that identifies each eligible human and issues that
+human a number of ration coins for the respective rationing period. An RA
+largely functions like a regular exchange, except that eligible humans will
+need to authenticate directly to withdraw rations (instead of transferring
+fiat to an exchange). Merchants selling rationed goods will be (legally)
+required to collect deposit confirmations in proportion to the amount of
+rationed goods sold. A difference to regular exchanges is that RAs do not
+charge any fees. RAs may or may not allow refreshing rations that are about
+to expire for ration coins in the next period.
+
+Once an RA is added to a wallet, it should automatically try to withdraw the
+maximum amount of ration coins it is eligible for. Available rations should be
+shown below the subscriptions by RA (if any).
+
+ ..note::
+
+ RAs are considered an idea for future work and not part of our current timeline.
+
+
+Limited Donations per Capita (future work)
+------------------------------------------
+
+If per-capita limitations must be imposed on anonymous donations (for example
+for donations to political parties), an RA can be used to issue donation
+rations that limit the amount of donations that can be made for the respective
+period.
+
+ ..note::
+
+ RAs are considered an idea for future work and not part of our current timeline.
+
+
+
+Definition of Done
+==================
+
+ - Merchant backend support for multiple currencies
+ - Merchant backend support for consuming and issuing tokens
+ - Merchant SPA support for configuring new tokens of different types
+ - Wallet-core support for various new contract types
+ - Wallet-core filters for feasible contracts and possibly auto-executes subscriptions
+ - Wallet-GUIs (WebEx, Android, iOS) render new contract types
+ - Wallet-GUIs (WebEx, Android, iOS) allow user to select between multiple contracts
+ - Documentation for developers is up-to-date
+ - Token anonymity set size (ASS) authority implemented, documented
+ - Merchants report anonymity set size increases to ASS authority
+ - Wallets process anonymity set size reports from ASS authority
+ - Bachelor thesis written on applications and design
+ - Academic paper written on DONAU (requirements, design, implementation)
+ - DONAU implemented, documented
+ - DONAU receipt validation application implemented
+ - Integration tests exist in wallet-core
+ - Deliverables accepted by EC
+
+While rationing is part of the design, we expect the actual implementation to
+be done much later and thus should not consider it part of the "DONE" part.
+Rationing is complex, especially as a refunded contract should probably also
+refund the ration.
+
+
+Alternatives
+============
+
+The first draft of this DD included the capability of paying with multiple
+currencies for the same contract (for example, USD:1 and EUR:5) plus tokens
+and rations. However, this is very complex, both for wallets (how to display),
+for other merchant APIs (does the refund API have to become multi-currency as
+well?) and there does not seem to be a good business case for it. So for now,
+the price is always only in one currency.
+
+
+Drawbacks
+=========
+
+Significant change, but actually good ratio compared to use-cases covered.
+
+
+Discussion / Q&A
+================
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/047-stefan.rst b/design-documents/047-stefan.rst
new file mode 100644
index 00000000..4cef1865
--- /dev/null
+++ b/design-documents/047-stefan.rst
@@ -0,0 +1,172 @@
+DD 47: STEFAN
+#############
+
+Summary
+=======
+
+The Standardized Template for Effective-Fee Approximation Numbers (STEFAN)
+is a feature to ensure customers see consistent fees for equivalent
+purchases (largely) independent of the specific coins selected. It will also
+make it easier for merchants to configure their systems to pay all reasonable
+fees.
+
+
+Motivation
+==========
+
+Taler has a logarithmic fee structure for good reasons (to compete in
+different market segments with reasonable profit margins). However, the
+logarithmic fee structure inherently implies that the specific coin selection
+made by the wallet can result in very different fees being applicable for the
+same amount at the same merchant merely due to different coins being available
+in the wallet. To minimize support costs, it is important that customers do
+not need to be aware of the concept of coins and are instead shown consistent
+fees for equivalent transactions.
+
+
+Requirements
+============
+
+ - keep the logarithmic nature of the fees (proportionally high fees
+ for tiny amounts, medium fees for medium amounts, low fees for large amounts)
+ - same purchase, same perceived price; prices are predictable for users
+ - enable merchants to easily cover all fees in most cases
+
+
+Proposed Solution
+=================
+
+The proposal is for the exchange to advertise three STEFAN-parameters that
+encode a fee curve of the form ``stefan_abs + stefan_log * log P +
+stefan_lin * P`` where P represents the gross price to be paid.
+Here, the numerical value for P is to be computed by
+dividing the actual gross price by the smallest denomination
+offered by the exchange.
+
+.. note::
+
+ This calculation is already done using floating point (!) as we want the
+ STEFAN-curve to be smooth and not a step-function. This is also needed so
+ that we can invert the computation and calculate gross amounts from net
+ amounts and actually get a nice invertible computation where both
+ directions always match. Note that the computation itself is nevertheless
+ non-trivial involving Newton's method to solve ``f(x)=0`` using a
+ well-estimated starting point for the iteration to avoid divergence issues.
+ Finally, while we do the STEFAN-curve computations using doubles, we should
+ then convert the final amounts back into "human-friendly" numbers rounding
+ towards the nearest value that can be represented using the canonical
+ number of decimal places at the exchange. libtalerexchange (C) has a
+ reference implementation of the gross-net conversion functions (in both
+ directions) and of the final rounding logic. This exception to the general
+ rule of no floating-points for amounts is acceptable as it is not actually
+ done at the protocol level but only in internal computations of the wallet
+ and merchant backend as part of the STEFAN cost estimation logic, which by
+ definition is an estimate and does not need to be exact. (And even if
+ wallet and merchant backend were to (slightly) disagree about the
+ computations due to different floating point implementations, everything
+ would still be fine, and even a significant disagreement would not cause
+ anything but resurface the UI issue the STEFAN-curves addresses.)
+
+The fee curve will be the displayed fee, except in cases where the coin
+selection is exceptionally bad (which should happen in substantially less than
+1% of all cases). The fee curve will also be used as the maximum fee a
+merchant will cover unless the merchant overrides the mechanism.
+
+In the most common case, where the STEFAN-curve fee is at or below what the
+merchant covers, no fees are displayed, except in the exceptionally rare
+case where the actual fees (due to unfortunate coin selection) are above
+both the exchange's STEFAN-curve and the what the merchant covers. In this
+last case the fees shown will be the actual fees minus what the merchant
+covers and here the fees may vary even for equivalent transactions.
+
+In the uncommon case where a merchant does not cover any fees or only covers
+parts of the fee according to the STEFAN-curve, the displayed fee will be the
+value on the STEFAN-curve minus the amount covered by the merchant. If the
+actual fees paid end up being below the approximation by the STEFAN-curve, the
+delta is (by default) *hidden* from the balance of the user to simulate a
+consistent fee.
+
+However, only the total available balance is marked down based on the
+STEFAN-curve value. Thus, the wallet will contains coins with a potentially
+higher balance value than what is shown to the user. This difference is
+reconciled annually by adding a special transaction that increases the wallet
+balance to eliminate the difference without any actual network interaction.
+The entry in the transaction history that boosts the balance links to an
+explanation. We may consider suggesting the user to donate the windfall.
+
+In developer mode, the user should probably be given the choice to see the
+delta, to disable the feature, and/or to force the windfall transaction to
+happen immediately.
+
+
+Computing the curve
+-------------------
+
+Typically, the ``stefan_abs`` value should represent a single wire transfer
+fee. The ``stefan_log`` value should be computed to approximate the deposit
+(and if applicable) refresh and withdraw fees for a coin, to be multiplied by
+the number of coins. In a canonical setup, ``stefan_lin`` would be zero.
+However, if an exchange is configured to use a linear fee structure, then
+``stefan_lin`` would become applicable.
+
+The taler-wallet-cli should have an option to compute the STEFAN-values
+given a denomination fee structure. This computation could probably be done
+either analytically (if the fee structure is systematic) or by simulation.
+
+Modifications to the merchant
+-----------------------------
+
+Instead of having (just) a "default fee", merchants should have an option to
+use the STEFAN-curve when computing the fees they would be willing to cover.
+
+Modifications to the exchange
+-----------------------------
+
+The STEFAN-curve can be configured using three simple configuration values
+in the ``[exchange]`` section. The resulting values should be shared as
+part of the ``/keys`` response, without digital signature.
+
+Modifications to the wallets
+----------------------------
+
+The STEFAN-curves will be useful as an easy approximate way to compare
+exchange fee structures. However, wallets may not want to just trust an
+exchange to honestly report STEFAN-curve values but could possibly use
+a simulation to check that the given STEFAN-curve matches the actual fees.
+
+Wallets will need to keep the hidden STEFAN-balance and add the annual
+internal reconcilliation transaction.
+
+Wallets will need to compute both the STEFAN-fee for display and still
+do their own internal actual coin selection to minimize fees.
+
+
+
+Definition of Done
+==================
+
+ - exchange modified (DONE)
+ - merchant understands STEFAN curve in backend (DONE)
+ - merchant SPA has configuration option to enable use of STEFAN-curves
+ - wallet-core uses STEFAN-curves to compute display fees
+ - wallet-core supports annual reconcilliation transaction
+ - wallet GUIs use STEFAN-curves when comparing exchange fee structures
+
+
+Alternatives
+============
+
+Refresh fees could additionally be waived if the refresh operation yields coins
+of a lower denomination than the original coin. We should check if this allows
+us to define tighter STEFAN-curves.
+
+
+Drawbacks
+=========
+
+
+
+Discussion / Q&A
+================
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/048-wallet-exchange-lifecycle.rst b/design-documents/048-wallet-exchange-lifecycle.rst
new file mode 100644
index 00000000..75ec3afb
--- /dev/null
+++ b/design-documents/048-wallet-exchange-lifecycle.rst
@@ -0,0 +1,144 @@
+DD 48: Wallet Exchange Lifecycle and Management
+###############################################
+
+Summary
+=======
+
+This design document covers the lifecycle and management
+of exchanges in the wallet.
+
+Motivation
+==========
+
+The current wallet implementation lacks requests to manage exchanges.
+It also always fetches the /keys info of all exchanges, because it doens't
+distinguish between used and preset/added exchanges.
+
+Requirements
+============
+
+The following properties of of exchanges managed by the wallet
+are important:
+
+* is the exchange used for something (coins, (account-)reserves, purses, ...)
+* did the user (ever) accept the ToS?
+* does the exchange have newer ToS available?
+* is a current version of /keys (including former /wire) downloaded?
+* were there errors downloading or checking the keys info?
+* is the exchange permanently added or ephemeral?
+
+ * ephemeral exchange records are created when the user
+ checks fees of an exchange but doesn't use it,
+ they would typically be hidden in the UI
+
+
+Proposed Solution
+=================
+
+Exchange Entry Status
+---------------------
+
+The wallet exposes three separate status fields for each exchange entry:
+
+* the entry status
+* the update status
+* the ToS status
+
+
+Entry Status
+~~~~~~~~~~~~
+
+* ``preset``: Exchange record has been added to the exchange (typically as
+ a hardcoded preset in wallet-core). While the exchange can be selected for operations,
+ the wallet doesn't update the status yet, i.e. no /keys queries are done.
+* ``ephemeral``: Exchange has been updated (or update has been attempted) at
+ least once (for example as part of checking the fees for a transaction using
+ the exchange). However, the exchange is not yet used for any resource in the wallet.
+ In this state, the exchange record will be garbage-collected eventually.
+* ``used``: The exchange is known and used, the wallet regularly queries /keys.
+
+Transitions:
+
+* A transition from ``used`` to ``ephemeral`` is not possible,
+ since this would eventually remove preset exchanges and likely confuse
+ the user.
+
+Update Status
+~~~~~~~~~~~~~
+
+* ``initial``: Not updated, no need to update
+* ``initial-update``: Update pending, possibly with error
+* ``suspended``: Exchange was manually disabled, should not be contacted
+ anymore, but record is kept in the wallet. Mostly useful for testing.
+* ``unavailable-update``: The exchange is currently unavailable to be used for withdrawals,
+ but it is possible that the exchange starts working again in the future.
+ The wallet will re-try contacting the exchange. The wallet will still try
+ operations that *spend* coins, but the user might be warned about the bad
+ exchange status.
+
+ Examples:
+
+ * The exchange updated to a new protocol version that is incompatible with the wallet
+ * The exchange advertises a new master public key. This might be a temporary
+ configuration issue or malicious attack.
+ * The exchange only advertises outdated denomination keys, making new withdrawals
+ impossible.
+* ``ready``: Exchange is useable.
+* ``ready-update``: Exchange is useable, but currently being updated.
+
+ToS Status
+~~~~~~~~~~
+
+* ``pending``: The wallet is still trying to download the ToS.
+ Possibly the last download attempt failed, will be reflected in an
+ error details object.
+* ``proposed``: The user needs to accept the current ToS.
+* ``accepted``: The user has accepted the latest version of the ToS.
+
+Management Requests
+-------------------
+
+* ``listExchanges``: List exchanges with their status info.
+* ``addExchange``: Adds an exchange, entry status will be ``ephemeral``
+ until the user actually uses the exchange.
+* ``getExchangeResources``: List resources (number of coins, reserves, ...) associated
+ with the exchange.
+* ``deleteExchange({exchangeUrl: string, purge: boolean})``: Removes an exchange.
+ Unless ``purge: true`` is specified, only an exchange without any associated
+ resources can be deleted.
+* ``getExchangeTos({exchangeUrl: string, acceptLanguage?: string[], acceptFormat?: string[]}) => { language: string, mime: string, content: string, altLanguages: string[] }``
+
+FIXME: Purging should probably delete *all* resources associated with the exchange.
+But does it also remove the associated transactions?
+
+ToS Management
+--------------
+
+The wallet only stores the last accepted ToS ETag and the ETag last offered by
+the exchange. The ToS contents are not stored by the wallet database (and thus
+not included in backups). However, the wallet implementation may cache the
+``/terms`` response on the level of the HTTP client.
+
+In future iterations, the UI might specify the prefered language and content type
+for ``/terms``, so that the wallet can already download the full response (not just ``HEAD``).
+
+
+Definition of Done
+==================
+
+ * states implemented in wallet-core
+ * exchange management specified on a UI level
+ * webex implemented
+ * android wallet implemented
+ * ios wallet implemented
+
+Discussion / Q&A
+================
+
+* Should there be a "permanently failed" update state?
+
+ * dold => I don't think so, as it means that temporary configuration issues on the side of the
+ exchange might *permanently* brick users' wallets.
+ The wallet should always re-try contacting the exchange and of course possibly report
+ information to the auditor.
+
diff --git a/design-documents/049-auth.rst b/design-documents/049-auth.rst
new file mode 100644
index 00000000..d328aabf
--- /dev/null
+++ b/design-documents/049-auth.rst
@@ -0,0 +1,154 @@
+DD 49: Authentication
+#####################
+
+Summary
+=======
+
+This design document specifies a simple authentication framework to be used by multiple Taler
+components that require authentication.
+
+Motivation
+==========
+
+SPAs currently store the username and password in locals storage (or at least
+session storage).
+
+There's also no way to manage auth tokens third parties (e.g.
+auditors).
+
+Requirements
+============
+
+* simple specification
+* simple implementation
+* simple to use
+* must cover two main use cases:
+
+ * SPA login
+ * delegating (possibly restricted) access to a third party using a token
+
+Proposed Solution
+=================
+
+We define a ``token`` endpoint that can be used to obtain access tokens from
+other forms of authentication, typically HTTP Basic auth.
+
+
+.. _dd48-token:
+
+Token Endpoint
+--------------
+
+.. http:post:: /${RESOURCE...}/token
+
+ **Request Body**
+
+ .. ts:def:: TokenRequest
+
+ interface TokenRequest {
+ // Service-defined scope for the token.
+ // Typical scopes would be "readonly" or "readwrite".
+ scope: string;
+
+ // Server may impose its own upper bound
+ // on the token validity duration
+ duration?: RelativeTime;
+
+ // Is the token refreshable into a new token during its
+ // validity?
+ // Refreshable tokens effectively provide indefinite
+ // access if they are refreshed in time.
+ refreshable?: boolean;
+ }
+
+ **Response:**
+
+ :http:statuscode:`200 Ok`:
+ The response is a `TokenSuccessResponse`
+
+ **Details:**
+
+ .. ts:def:: TokenSuccessResponse
+
+ interface TokenSuccessResponse {
+ // Expiration determined by the server.
+ // Can be based on the token_duration
+ // from the request, but ultimately the
+ // server decides the expiration.
+ expiration: Timestamp;
+
+ // Opque access token.
+ access_token: string;
+ }
+
+Token Revocation
+-----------------
+
+Clients using session tokens log by forgetting the session token.
+Tokens can be explicitly revoked by making a ``DELETE`` request on
+the token endpoint.
+
+.. http:delete:: /${RESOURCE...}/token
+
+ Invalidate the access token that is being used to make the request.
+
+ **Authentication:** The client must authenticate
+ with a valid access token.
+
+
+
+Definition of Done
+==================
+
+* DONE: spec reviewed
+* DONE: implemented in merchant backend
+* implemented in libeufin-bank
+* DONE: implemented in the bank webui SPA
+* implemented in the merchant backoffice SPA
+
+
+Alternatives
+============
+
+* use something much closer to OAuth2
+
+ * would be unnecessarly generic and complex
+
+Session Tokens / Signatures
+---------------------------
+
+For performance reasons, OAuth 2.0 uses two types of tokens: Short-lived access
+tokens and long-lived refresh tokens. The access tokens can be implemented via
+signatures and the long-lived refresh tokens via server-stored tokens. This
+allows to cheaply validate access tokens, while still allowing longer expiration times
+for refresh tokens.
+
+We could do something similar by introducing login and session tokens. A login
+token is a server-stored token. In addition to being used directly as an
+access token, a login token can also be converted to a short-lived session
+token.
+
+Session access tokens should be implemented as "self-encoded tokens", i.e.
+as tokens signed by the server without requiring server-side token storage.
+Session access tokens should have a rather short maximum expiration.
+
+The signature should be over ``(username, kind, scope, creation_timestamp, expiry)``.
+
+To revoke session tokens, the server must store the timestamp of the last
+revocation and only accept tokens with a ``creation_timestamp`` larger than the
+last revocation timestamp. Individual session tokens cannot be revoked, only
+all issued session tokens can be revoked at once.
+
+However, we decided against doing this because the performance benefits
+are not significant enough for us and having multiple token types would
+lead to unnecessary complexity.
+
+Drawbacks
+=========
+
+* still more complex than simple auth tokens or HTTP basic auth
+
+Discussion / Q&A
+================
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/050-libeufin-nexus.rst b/design-documents/050-libeufin-nexus.rst
new file mode 100644
index 00000000..6049bda6
--- /dev/null
+++ b/design-documents/050-libeufin-nexus.rst
@@ -0,0 +1,354 @@
+DD 50: Libeufin-Nexus
+#####################
+
+Summary
+=======
+
+This document proposes a new design for the libeufin Nexus component,
+focusing on the user-interaction and where what state is to be stored.
+
+
+Motivation
+==========
+
+The existing Nexus design is overly complex to configure, develop and
+maintain. It supports EBICS features we do not need, and lacks key features
+(like long-polling) that are absolutely needed.
+
+..
+ long-polling at the TWG is NOT NetzBon-critical, as the TWG is only offered
+ by the Bank.
+
+We also have several implementations with Nexus, Bank and Depolymerization
+subsystems, and it would be good to combine some of them.
+
+Requirements
+============
+
+ * Easy to use, high-level abstraction over EBICS details
+ * Reduce complexity, no multi-account, multi-connection support
+ * No general EBICS client, Taler-specific logic
+ * Support for Taler facade, including bouncing of transactions with malformed subject
+ * Clear separation between configuration and runtime, minimal runtime footprint
+ * No built-in cron-jobs, background tasks runnable via systemd (one-shot and persistent mode)
+ * Configuration style same as other GNUnet/Taler components
+ * No private keys in database, as in other Taler components
+ * Enable future unified implementation with Depolymerization to share database and REST API logic
+
+Proposed Solution
+=================
+
+Split up Nexus into four components:
+
+ * nexus-ebics-setup: register account with EBICS server and perform key generation and exchange
+ * nexus-ebics-fetch: obtain wire transfers and payment status from EBICS server
+ * nexus-ebics-submit: send payment initiation messages to EBICS server
+ * nexus-httpd: serve Taler REST APIs (wire gateway API, revenue API) to Taler clients and implement facade logic
+
+All four components should read a simple INI-style configuration file,
+possibly with component-specific sections.
+
+Configuration file
+------------------
+
+.. code-block:: shell-session
+
+ [nexus-ebics]
+ CURRENCY = EUR
+ HOST_BASE_URL = http://ebics.bank.com/
+ HOST_ID = mybank
+ USER_ID = myuser
+ PARTNER_ID = myorg
+ IBAN = MY-IBAN
+ BIC = MY-BIC
+ NAME = MY NAME
+ BANK_PUBLIC_KEYS_FILE = enc-auth-keys.json
+ CLIENT_PRIVATE_KEYS_FILE = my-private-keys.json
+ BANK_DIALECT = postfinance # EBICS+ISO20022 style used by the bank.
+
+ [nexus-postgres]
+ CONFIG = postgres:///libeufin-nexus
+
+ [nexus-ebics-fetch]
+ FREQUENCY = 30s # used when long-polling is not supported
+ STATEMENT_LOG_DIRECTORY = /tmp/ebics-messages/
+
+ [nexus-ebics-submit]
+ FREQUENCY = 30s # use 0 to always submit immediately (via LISTEN trigger)
+
+ [nexus-httpd]
+ PORT = 8080
+ UNIXPATH =
+ SERVE = tcp | unix
+
+ [nexus-httpd-wire-gateway-facade]
+ ENABLED = YES
+ AUTH_METHOD = token
+ AUTH_TOKEN = "secret-token:foo"
+
+ [nexus-httpd-revenue-facade]
+ ENABLED = YES
+ AUTH_METHOD = token
+ AUTH_TOKEN = "secret-token:foo"
+
+
+File contents: BANK_PUBLIC_KEYS_FILE
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+JSON with 3 fields:
+
+ * bank_encryption_public_key (base32)
+ * bank_authentication_public_key (base32)
+ * accepted (boolean)
+
+File contents: CLIENT_PRIVATE_KEYS_FILE
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+JSON with:
+
+ * signature_private_key (base32)
+ * encryption_private_key (base32)
+ * authentication_private_key (base32)
+ * submitted_ini (boolean)
+ * submitted_hia (boolean)
+
+Database schema
+---------------
+
+.. code-block:: shell-session
+
+ CREATE TABLE incoming_transactions
+ (incoming_transaction_id INT8 GENERATED BY DEFAULT AS IDENTITY
+ ,amount taler_amount NOT NULL
+ ,wire_transfer_subject TEXT
+ ,execution_time INT8 NOT NULL
+ ,debit_payto_uri TEXT NOT NULL
+ ,bank_transfer_id TEXT NOT NULL -- EBICS or Depolymerizer (generic)
+ ,bounced BOOL DEFAULT FALSE -- to track if we bounced it
+ );
+
+ CREATE TABLE outgoing_transactions
+ (outgoing_transaction_id INT8 GENERATED BY DEFAULT AS IDENTITY
+ ,amount taler_amount NOT NULL
+ ,wire_transfer_subject TEXT
+ ,execution_time INT8 NOT NULL
+ ,credit_payto_uri TEXT NOT NULL
+ ,bank_transfer_id TEXT NOT NULL
+ );
+
+ CREATE TABLE initiated_outgoing_transactions
+ (initiated_outgoing_transaction_id INT8 GENERATED BY DEFAULT AS IDENTITY -- used as our ID in PAIN
+ ,amount taler_amount NOT NULL
+ ,wire_transfer_subject TEXT
+ ,execution_time INT8 NOT NULL
+ ,credit_payto_uri TEXT NOT NULL
+ ,out_transaction_id INT8 REFERENCES outgoing_transactions (out_transaction_id)
+ ,submitted BOOL DEFAULT FALSE
+ ,hidden BOOL DEFAULT FALSE -- FIXME: exaplain this.
+ ,client_request_uuid TEXT NOT NULL UNIQUE
+ ,failure_message TEXT -- NOTE: that may mix soon failures (those found at initiation time), or late failures (those found out along a fetch operation)
+ );
+
+ COMMENT ON COLUMN initiated_outgoing_transactions.out_transaction_id
+ IS 'Points to the bank transaction that was found via nexus-fetch. If "submitted" is false or nexus-fetch could not download this initiation, this column is expected to be NULL.'
+
+nexus-ebics-setup
+-----------------
+
+The ebics-setup tool performs the following:
+
+ * Checks if the require configuration options are present and well-formed
+ (like the file names), if not exits with an error message. Given
+ --check-full-config, also sanity-check the configuration options of the
+ other subsystems.
+
+ * Checks if the private keys file exists, if not creates new private keys
+ with flags "not submitted".
+
+ * If any private key flags are set to "not submitted" or a command-line
+ override is given (--force-keys-resubmission), attempt to submit the
+ corresponding client public keys to the bank. If the bank accepts the
+ client public key, update the flags to "submitted".
+
+ * If a public key was submitted or if a command-line override
+ (--generate-registration-pdf) is given, generate a PDF with the public key
+ for the user to print and send to the bank.
+
+ * Checks if the public keys of the bank already exist on disk, if not try to
+ download them with a flag "not accepted". If downloading fails, display a
+ message asking the user to register the private keys (and give override
+ options for re-submission of private keys or re-generation of the
+ registration PDF).
+
+ * If we just downloaded public keys, display the corresponding public keys
+ (or fingerprints) to the user and ask the user to interactively confirm to
+ accept them (or auto-accept via --auto-accept-keys). If the user accepted
+ the public key, update the flag to "accepted".
+
+nexus-ebics-fetch
+-----------------
+
+ * Fetches by default all incoming and outgoing bank transactions and error
+ messages and inserts them into the Postgres database tables (including
+ updating the initiated outgoing transaction table). First, considers the
+ last transactions in the database and fetches statements from that day
+ forward (inclusive). Afterwards, fetches reports and when the day rolls
+ over (before committing any transactions with the next day!) also fetches a
+ final statement of the previous day, thus ensuring we get a statement
+ every day plus intra-day reports.
+
+ .. note::
+
+ (1) "from that day forward (inclusive)" must **not** rely on EBICS returning
+ the unseen messages: that's because they might **already** be downloaded but
+ never made it to the database.
+
+ (2) "and when the day rolls over". When does a day roll over? => A day rolls
+ over when the current time is at least on the day after the transaction with the
+ most recent timestamp that's stored in the database.
+
+ (3) "Afterwards, fetches reports". This must happen **only after** any possible
+ previous statement got downloaded.
+
+ To summarize: at any point in time the database must contain (the content of) any
+ possible statement up to the current time, plus any possible report up to the current
+ time (in case that's not covered by any statement so far).
+
+ * Bounces transactions with mal-formed wire transfer subjects.
+
+ * Optionally logs EBICS messages to disk, one per file, based on
+ configuration. Filenames must include the timestamp of the download. The
+ date must be in the path and the time of day at the beginning of the
+ filename. This will facilitate easy deletion of logs.
+
+ * Optionally only fetches reports (--only-reports) or statements (--only-statements)
+ or only error messages (--only-failures).
+
+ * Optionally terminates after one fetch (--transient) or re-fetches based
+ on the configured frequency.
+
+ * Terminates hard (with error code) if incoming transactions are not in the
+ expected (configured) currency.
+
+
+nexus-ebics-submit
+------------------
+
+ * Generates a payment initiation message for all client-initiated outgoing
+ transactions that have not yet been initiated. If the server accepts the
+ message, sets the initiated flag in the table to true. The EBICS order ID
+ is set to the lowest initiated_outgoing_transaction_id in the transaction
+ set modulo 2^20 encoded in BASE36. The payment information ID is set to
+ the initiated_outgoing_transaction_id of each transaction as a text
+ string. The message identification is set to the lowest
+ initiated_outgoing_transaction_id plus ("-") the highest
+ initiated_outgoing_transaction_id as a text string.
+
+ * Optionally terminates after one fetch (--transient) or re-submits based
+ on the configured frequency.
+
+ * If configured frequency is zero (default), listens to notifications from
+ nexus-httpd for insertions of outgoing payment initiation records.
+
+
+nexus-httpd
+-----------
+
+ * Offers REST APIs as per configuration.
+
+ * Listens to notifications from nexus-ebics-fetch to run facade-logic and
+ wake-up long pollers.
+
+ * Offers a *new* REST API to list failed (initiated outgoing) transactions
+ and allows the user to re-initiate those transactions (by creating new
+ records in the initiated outgoing transactions table). Also allows the
+ user to set the "hidden" flag on failed transactions to not show them
+ anymore.
+
+
+Definition of Done
+==================
+
+ * Code implemented
+ * Testcases migrated (including exchange, merchant, etc.)
+ * Man pages updated
+ * Manual updated
+ * Tested with actual banks (especially error handling and idempotency)
+ * Tested against server-side EBICS mock (to be resurrected)
+ * Tested against various ISO 20022 messages
+
+
+Alternatives
+============
+
+ * Only run Taler on top of Bitcoin.
+
+Drawbacks
+=========
+
+ * Uses EBICS.
+
+Discussion / Q&A
+================
+(This should be filled in with results from discussions on mailing lists / personal communication.)
+
+* From private discussion: bouncing goes inside nexus-fetch as
+ it saves one database event, makes the HTTPd simpler, and lets
+ the bouncing happen even when no HTTPd runs.
+
+* Sign-up PDF is ever only generated if *both* INI & HIA have the "submitted" state.
+
+* What is 'override option for re-submission of private keys?'.
+ --force-keys-submission already re-submits the keys but it does not
+ override them. If the user wants new keys, they can easily remove
+ the keys file on disk. That makes the CLI shorter.
+
+* Implementation sticks to the IBAN found in the configuration, **if** the bank
+ does not show any IBAN related to the EBICS subscriber.
+
+* from nexus-ebics-submit: "if the server accepts the request, sets the
+ initiated flag in the table to true". May there be a case where the
+ server accepted the request, but the client never got any response (some
+ network issue..), and therefore didn't set the submitted flag, ending
+ up in submitting the payment twice? Also: flagging the payment _after_
+ the bank response, may lead double-submission even if the HTTP talk ended
+ well: it suffices to crash after having received a "200 OK" response but
+ before setting the submitted flag to the database.
+
+* the ebics-submit section mentions the EBICS order ID. The following excerpt
+ was found however at page 88 of the EBICS 3 specifications:
+
+ ``OrderID is only present if a file is transmitted to the bank relating to an order with an
+ already existing order number (only allowed for AdminOrderType = HVE or HVS)``
+
+ Nexus does not support HVE or HVS.
+
+* As of private communication, the responsibility of submitting idempotent payments
+ relies on the use of ``request_uid`` (a database column of the initiated payment)
+ as the ``MsgId`` value of the corresponding pain.001 document.
+
+* ``submitted`` column of an initiated payment evolved into the following enum:
+
+ .. code-block:: shell-session
+
+ CREATE TYPE submission_state AS ENUM (
+ 'unsubmitted'
+ ,'transient_failure'
+ ,'permanent_failure'
+ ,'success'
+ ,'never_heard_back'
+ );
+
+ * ``unsubmitted``: default state when a payment is initiated
+ * ``transient_failure``: submission failed but can be retried, for example after a network issue.
+ * ``permanent_failure``: EBICS- or bank-technical error codes were not EBICS_OK (nor any tolerated EBICS code like EBICS_NO_DOWNLOAD_DATA_AVAILABLE), never retry.
+ * ``never_heard_back``: the payment initiation submission has **been** ``success`` but it was never confirmed by any outgoing transaction (from a camt.5x document) or any pain.002 report. It is responsability of a garbage collector to set this state after a particular time period.
+
+* the initiated_outgoing_transactions table takes two more columns:
+ ``last_submission_date``, a timestamp in microseconds, and a
+ ``submission_counter``. Both of them would serve to decide retry
+ policies.
+
+* the ``failure_text`` column at the initiated_outgoing_transactions table
+ should contain a JSON object that contains any useful detail about the problem.
+ That *could* be modeled after the Taler `ErrorDetail <https://docs.taler.net/core/api-common.html#tsref-type-ErrorDetail>`_, where at least the error code and the hint fields are provided.
diff --git a/design-documents/051-fractional-digits.rst b/design-documents/051-fractional-digits.rst
new file mode 100644
index 00000000..4321fd53
--- /dev/null
+++ b/design-documents/051-fractional-digits.rst
@@ -0,0 +1,211 @@
+DD 51: Fractional Digits
+#########################
+
+Summary
+=======
+
+This design document specifies how an amount's fractional digits should be rendered.
+Note that UIs that cannot render amounts as specified (e.g. because the display does
+not support super script digits) may ignore the rendering advice provided by the
+protocol under this DD.
+
+
+Motivation
+==========
+
+Since different currencies have different ways to show/render fractionals, the
+end-user apps should follow these guidelines.
+
+Requirements
+============
+
+There was already a specification for ScopedCurrencyInfo - which got renamed to CurrencySpecification.
+
+We need three core characteristics for fractional digits for each currency:
+
+ e) the number of fractional digits e in [0..8] the user may 'e'nter in a TextInputField
+
+ n) the number of fractional digits n in [0..8] to be rendered as 'n'ormal characters (same font and size as the integer digits). All additional fractional digits will be rendered as SuperScriptDigits as known from gas filling stations. The UI should never round or truncate any amount, but always render all existing digits (except trailing zeroes, see c).
+
+ z) the number of fractional digits z in [0..8] to be rendered as trailing 'z'eroes (including SuperScript digits). E.g. if z = 2 (and n = 2), then render $5 as ``$ 5.00``. If z = 3 (and n = 2), then render $5 as ``$ 5.00⁰`` with two normal trailing zeroes and one superscript trailing zero.
+
+The values e, n, and z are independent from each other. Each could be any value
+from 0 to 8. However, when a user enters an amount, s/he should be able to input
+all normal fractionals. Thus e should never be smaller than n.
+
+Usually, all these three numbers have the same value (e = n = z), which means
+that in case of e.g. '2' (used for €,$,£) the user can enter cent/penny values
+(but not a fraction of those), these cents/pennies are always shown (even if
+they are 0) as two normal digits after the decimal separator, and fractions of
+a cent/penny are rendered as SuperScriptDigits, but appear only if they are not
+trailing zeroes.
+For japanese ¥, all three values could be 0, which means that the user cannot
+enter fractions at all. If there are fractions they would never be rendered as
+normal digits but always as SuperScript, and appear only if they are not
+trailing zeroes.
+
+Additionally, some cryptocurrencies have such huge units, that they are
+commonly rendered in milli-units, such as mBTC (milliBTC, 1/1000 of a BTC),
+Gwei (Giga-WEI), Mwei (Million-WEI), Kwei (Kilo-WEI), or
+Mether/Kether/Gether/Tether and more "logical" units such as Szabo and
+Finney. See ``https://coinguides.org/ethereum-unit-converter-gwei-ether/`` if
+you want a good laugh. Regardless of the self-inflicted insanity here, this
+could also make sense for inflated currencies in some cases. So we probably
+should also have the ability to ship such a conversion map.
+
+
+Proposed Solution
+=================
+
+Protocol considerations
+-----------------------
+
+The exchange, bank and merchant backends would need to be configured (via
+their configuration files) to return the following CurrencySpecification in their
+``/config`` and/or ``/keys`` endpoints. The bank returns this so that the
+bank SPA can render amounts correctly, the exchange informs the wallets about
+the desired way to render the currency, and the merchant backend informs the
+merchant SPA --- independently of any particular exchange being used --- how
+the merchant SPA should render amounts. Hence, the information will need to be
+provisioned by all three services.
+
+ .. code-block:: swift
+
+ public struct CurrencySpecification: Codable, Sendable {
+ // e.g. “Japanese Yen” or "Bitcoin (Mainnet)"
+ let name: String
+ // how many digits the user may enter after the decimal separator
+ let fractional_input_digits: Int
+ // €,$,£: 2; some arabic currencies: 3, ¥: 0
+ let fractional_normal_digits: Int
+ // usually same as fractionalNormalDigits, but e.g. might be 2 for ¥
+ let fractional_trailing_zero_digits: Int
+ // map of powers of 10 to alternative currency names / symbols,
+ // must always have an entry under "0" that defines the base name,
+ // e.g. "0 : €" or "3 : k€". For BTC, would be "0 : BTC, -3 : mBTC".
+ // This way, we can also communicate the currency symbol to be used.
+ let alt_unit_names: [Int : String]
+ }
+
+(Note: decimal_separator, group_separator and is_currency_name_leading were
+removed from this struct since they should always be taken from the user's
+locale.)
+
+
+
+
+For very large (2400000) or very tiny amounts (0.000056) the software would
+then first represent the number compactly without any fraction (so for our
+examples above, 24 * 10^6 and 56 * 10^-6) and then search for the nearest fit
+in the alt_unit_names table. The result might then be 24000 KGELD or 0.056
+mGELD, assuming the map had entries for 3 and -3 respectively. Depending on
+the table, the result could also be 24 MGELD (6 : MGELD), or 5.6 nGELD
+(assuming -6 : nGeld). Fractional rendering rules would still be applied
+to the alternative unit name, alas the "fractional_input_digits" would
+always apply to the unit currency and may need to be adjusted if amounts
+are input using an alternative unit name.
+
+Configuration syntax
+--------------------
+
+Each currency should be specified in its own subsystem-independent
+currency, with the section name prefixed with "currency-". In that
+section. The map could be given directly in JSON. For example:
+
+ .. code-block:: ini
+
+ [currency-euro]
+ ENABLED = YES
+ name = "Euro"
+ code = "EUR"
+ fractional_input_digits = 2
+ fractional_normal_digits = 2
+ fractional_trailing_zero_digits = 2
+ alt_unit_names = {"0":"€"}
+
+ [currency-japanese-yen]
+ ENABLED = YES
+ name = "Japanese Yen"
+ code = "JPY"
+ fractional_input_digits = 2
+ fractional_normal_digits = 0
+ fractional_trailing_zero_digits = 2
+ alt_unit_names = {"0":"¥"}
+
+ [currency-bitcoin-mainnet]
+ ENABLED = NO
+ name = "Bitcoin (Mainnet)"
+ code = "BITCOINBTC"
+ fractional_input_digits = 8
+ fractional_normal_digits = 3
+ fractional_trailing_zero_digits = 0
+ alt_unit_names = {"0":"BTC","-3":"mBTC"}
+
+ [currency-ethereum]
+ ENABLED = NO
+ name = "WAI-ETHER (Ethereum)"
+ code = "EthereumWAI"
+ fractional_input_digits = 0
+ fractional_normal_digits = 0
+ fractional_trailing_zero_digits = 0
+ alt_unit_names = {"0":"WAI","3":"KWAI","6":"MWAI","9":"GWAI","12":"Szabo","15":"Finney","18":"Ether","21":"KEther","24":"MEther"}
+
+
+Implementation considerations
+-----------------------------
+
+iOS has a built-in currency formatter, which can be configured from a locale.
+It knows how to deal with group-separators and where to apply them (e.g. India
+uses a mixture of thousands and hundreds instead of putting the separator after
+each 3 digits like western currencies).
+Set the formatter's parameter 'maximumFractionDigits' to 8, then it will not
+round the value and thus can be used for the whole amount.
+Set its parameter 'minimumFractionDigits' to 'z' (fractionalTrailingZeroDigits)
+to let it automatically add trailing zeroes.
+Then convert all fractional digits after 'n' (fractionalNormalDigits) to
+SuperScript digits.
+
+(please add information about Android and WebEx here)
+
+
+
+Definition of Done
+==================
+
+(Only applicable to design documents that describe a new feature. While the
+DoD is not satisfied yet, a user-facing feature **must** be behind a feature
+flag or dev-mode flag.)
+
+ * Configuration (INI) format finalized and documented in taler.conf man page [DONE]
+ * Endpoints of libeufin-bank, fakebank, exchange and merchant return the information
+ * SPAs use the information to render amounts
+ * Wallet-core passes rendering information to wallet UIs
+ * Cashier, Android PoS, WebExtension, Android and iOS Wallet render amounts accordingly
+
+
+Alternatives
+============
+
+None, we cannot confuse users by rendering amounts in ways that break cultural
+standards, and we cannot round and have numbers in balances not add up.
+
+
+Drawbacks
+=========
+
+Discussion / Q&A
+================
+
+We probably should NOT have the decimalSeparator in this definition. Instead that
+should be taken from the locale of the user, so they see currency amounts formatted
+like they're used to.
+If we really keep this, then we would also need the groupSeparator to ensure it is
+not identical to the decimalSeparator.
+Better to leave this can of worms to the operating system our app runs on, and render
+according to the user's preferences (locale)...
+
+However, instead of decimalSeparator we could specify the locale this currency belongs to.
+
+
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/052-libeufin-bank-2fa.rst b/design-documents/052-libeufin-bank-2fa.rst
new file mode 100644
index 00000000..3d0900e2
--- /dev/null
+++ b/design-documents/052-libeufin-bank-2fa.rst
@@ -0,0 +1,136 @@
+DD 52: LibEufin Bank Two-factor authentification
+################################################
+
+Summary
+=======
+
+This document proposes designs for supporting 2-FA for more operations in
+libeufin-bank.
+
+Motivation
+==========
+
+Currently, only cashout operations are protected using 2-FA and we want to also
+protects withdrawal, transactions, account reconfiguration and account deletion.
+
+Requirements
+============
+
+* Support future TAN channels (YubiKey, trusted devices, etc) without API-breaking changes
+* Support multiple TAN channels per user
+
+Proposed Solutions
+==================
+
+2 kinds of operations
+^^^^^^^^^^^^^^^^^^^^^
+
+We have two kinds of operations we would like to protect:
+
+* state-machine operations that already have a ``pending`` and ``confirmed`` status and require multiple endpoint calls to complete (cashout and withdrawal).
+* one-shot operations that are currently completed using a single endpoint call (transaction, account reconfiguration and account deletion).
+
+Fine-grained or coarse-grained authentification
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* Fine-grained authorization is when one challenge is linked to a unique unalterable operation. They are the most secure and have the usability advantage that clients can show users exactly what they are allowing. They are complicated to implement especially for one-shot operations.
+* Coarse-grained authorization is when each challenge allows to perform one or many protected operations of any kind. They are the simplest to implement and might be enough for our needs.
+
+We should also take in consideration how hard it would be to maintain the solution and how hard it would be to protect a new kind of operation in the future.
+
+State machines operations only
+------------------------------
+
+If we transform all operations to become state-machine ones, we can use the same design currently used for cashout operations. All operations are created in a ``pending`` state and need to be confirmed later. The TAN challenge code is sent when the operation is created and checked during confirmation. Operation creation is idempotent and can be used to trigger code retransmission.
+
+The good
+^^^^^^^^
+
++ Fine-grained authorization
+
+The bad
+^^^^^^^
+
+- Requires to store pending operations in the database, requires new tables to store pending state for one-shot ones
+- Requires to add many endpoints to track operations status, list pending operations, confirm operations, etc
+- Requires to mix TAN challenge logic with operation logic, this means asking for TAN channel alongside operation data and returning TAN specific error in all operation creation and confirmation endpoints, therefore TAN logic changes can impact all those endpoints
+- Operation logic rewrite
+- Big backend and database change (new table or column and new API per operation)
+
+
+Centralized 2FA endpoints
+-------------------------
+
+To improve upon the previous design we can separate endpoints to perform TAN challenges from operation ones. When creating operations they return a challenge ID that can be used with TAN-specific endpoints to receive and solve a challenge. Those endpoints will handle the TAN channel choice and TAN-specific errors. Protected endpoints will error when a pending challenge hasn't been solved.
+
+The good
+^^^^^^^^
+
++ Fine-grained authorization
++ Centralized TAN challenge logic and error handling, TAN logic changes only impact TAN-specific endpoints
+
+The bad
+^^^^^^^
+
+- Requires to store pending operations in the database
+- Requires adding many endpoints to track operations status, confirm operations, list pending operations, etc.
+- Operation logic rewrite
+- Big backend and database change (new table or column and new API per operation)
+
+2FA tokens
+----------
+
+To improve upon the previous design, if coarse-grained authorization is enough, we can have a simpler design where a successful challenge produces a one-use 2FA token. Protected endpoints will error when a 2FA token is required and the token is provided through an HTTP header.
+
+We could require a 2FA token when confirming state-machine operations or when performing one-shot ones. Removing the need for new database tables and operation endpoints.
+
+The good
+^^^^^^^^
+
++ Existing database tables stay the same
++ Centralized TAN challenge logic and error handling
++ Most endpoints stay the same except the cashout API
++ Can protect new operations without changing their logic but need to add token consumption logic to the database transaction
++ Small backend and database change per operation (token consumption logic)
+
+The bad
+^^^^^^^
+
+- Using a nonstandard header can be complicated for some clients
+- The pending state of one-shot operations is kept at the client level, this is a simplification for the backend but we do not want to lose this state. This might be easy to do as all oneshot operations are simple ones and the token can be obtained in advance.
+- Coarse-grained authorization, one token for any operation. We could fix this by adding a ``kind`` field and an optional ``operation_id`` (state-machine operation) or ``operation_body`` (one-shot operations) field per challenge but this is ugly.
+
+2FA auth tokens
+---------------
+To improve upon the previous design, we could reuse the existing authentification token logic and create a new scope, ``2fa``, that works as an augmented ``readwrite``. Those auth tokens would be valid for a short amount of time (~3 minute) and would not be refreshable.
+
+The good
+^^^^^^^^
+
++ Existing database tables stay the same
++ Centralized TAN challenge logic and error handling
++ Most endpoints stay the same except the cashout API
++ Can protect new operations without changing their logic
++ Trivial backend and database change per operation (one line of code per operation)
+
+The bad
+^^^^^^^
+
+- Having a short-term token in addition to a long-term refreshable token can be confusing for clients.
+- We still keep the pending state of one-shot operations at the client level.
+- Coarse-grained authorization, one token for any operation for a short amount of time.
+
+Q / A
+=====
+
+* Q: Where do we want to handle TAN challenges logic and error handling, in each operation API or a TAN-specific API?
+
+ * In each operation means fewer API calls and TAN-specific means more API calls but better/cleaner logic separation.
+
+* Q: Where do we want to store pending states for oneshot transactions in the client or the backend database?
+
+ * In the client makes things simpler for the backend but is incompatible with coarse-grained authorization.
+
+* Q: Do we need coarse-grained authorization or fine-grained is enough?
+
+ * Coarse-grained authorization requires that we store pending states for operations even for the ones that are currently oneshot. We could use a different strategy for each kind. \ No newline at end of file
diff --git a/design-documents/053-wallet-ui.rst b/design-documents/053-wallet-ui.rst
new file mode 100644
index 00000000..7b5fdf73
--- /dev/null
+++ b/design-documents/053-wallet-ui.rst
@@ -0,0 +1,1243 @@
+DD 53: Wallet UI Design
+#######################
+
+Summary
+=======
+
+This document proposes designs wallet UI. It defines what Android, iOS and
+WebExtension should follow in order to have a coherent UI between platforms.
+
+Motivation
+==========
+
+We want user to be able to help each others independent of the implementation
+they are using.
+We want user to be able to capitalize the effort of learning how to use one
+wallet and be able to use a different one without the need to learn
+anything new.
+Currently development of different platform specific implementation are independent
+and every developer needs to choose the layout, texts and buttons and navigation.
+
+Requirements
+============
+
+Every screen MUST be defined in a document with the following information:
+
+* **Identifiable UI screens**: every UI should have an unique identifier that will
+ be use for development discussion and bug reports. There should be an option
+ in the application to enable an active rendering of the id.
+
+* **Description**: the reason to be of the screen, should help to define what will
+ be included into, what is going to left for other screens and when and from
+ where should be linked.
+
+The screen MAY also have:
+
+* **Predefined assets**: every implementation should resue the same icons, images,
+ fonts and sounds.
+
+Additionaly the document COULD defined the components of the UI. If one of this
+properties is defined in the spec the implementation must implement it. The specification
+should be minimal to achieve the objective in the description.
+
+* **Info**. Spec of information that the user should have access. The type of info
+ could be a field (id and value) or a banner (information and instructions).
+ The spec will help to reuse the text for i18n across apps and defined
+
+* **Inputs**. Spec of information need to provide in current screen. The type of input,
+ range of values and validation should be defined if necessary.
+
+* **Actions**. Spec of buttons and interactable elements that will have a significant
+ change in the current state. It should also mention navigation when applicable.
+
+* **Layout**. Spec position of elements when needed. The spec should be "soft" in a sense
+ that elements should be easy to find following directions like "close to X" or
+ "at the start/end of the screen".
+
+* **Issues**. Issues we identified that need to be addressed in some implementation(s).
+ This is in particular about inconsistencies and bad design choices made on some
+ platforms.
+
+* **Adoption**. Things that one version does particularly
+ nice that we might want other implementations to adopt.
+
+* **Screenshots**. Should be provided for all wallet implementations and kept
+ up to date, to ensure that they can be used to aid in UI/UX and QA
+ discussions.
+
+Screen should be defined using the most relaxed definition that are good enough to
+be clear for the user. Platform will use this definition and adapt to the differences
+on the platform taking advantange of platform API and screen sizes.
+
+When a screen have multiple uses for the same purpose, a substate section should be
+included with the difference with the main definition.
+
+Part of the screens that are reused shoud also be defined in this document as screen.
+
+Common definition:
+ * navigation between screens should not happen if the user didn't take any action
+
+
+Proposed Solutions
+==================
+
+List of all screens with the defined properties.
+
+.. _cta-balance-list-ref:
+
+balance-list
+------------
+
+This screen shows a currency-scoped list of the balances stored in the wallet,
+and includes information about the total, incoming, and outgoing amounts, as
+well as the currency scope information for each item.
+
+Info
+^^^^
+
+* List of balances in the wallet, where each item contains:
+
+ * Total amount with currency (see :doc:`051-fractional-digits`).
+ * Incoming amount (money pending to arrive).
+ * Outgoing amount (money pending to leave).
+ * Currency scope information (see :doc:`035-regional-currencies`).
+
+* Strings to use:
+
+ * Title is "Balances"
+ * "inbound" and "outbound" are used with
+ pending amounts (shown if applicable below the main
+ amount, green for inbound, red for outbound)
+ * "pending" MAY be used as a badge label to indicate
+ that there are pending activities
+
+Layout
+^^^^^^
+
+* There SHOULD be a menu or button from where the QR code entry / scan
+ functionality is reachable (:ref:`cta-url-entry-ref`)
+* There SHOULD be a menu or button from where the settings screen (:ref:`cta-settings-ref`)
+ is reachable, unless settings are handled differently
+ on the platform.
+* In developer mode, there MAY be a menu or button
+ from where the developer tools (:ref:`cta-devtools-ref`)
+ are reachable. Alternatively, developer tools COULD
+ also only be reachable via settings.
+
+
+Issues
+^^^^^^
+
+* WebEx (minor): Inconsistent to aldready have
+ the "add" and "send" buttons on this page.
+* WebEx (image): Screenshot does not show any
+ pending transactions.
+* Android (text): Uses "Exchange:" which is
+ not user-facing terminology. Should only show the URLs.
+* Android (minor): Screenshot shows only a "pending"
+ badge, which seems redundant given "+10 KUDOS inbound"
+ (too much information?)
+* iOS (major): Way too much detail shown, way too
+ much explanation text, too many operations
+ (send money, request payment, spend test money!!!!);
+ Remove text "Balance:" within each currency, this
+ is all about *Balances* as per the title. Instead,
+ show the balance right of the currency name.
+* iOS (major): overly complex menu with balances and
+ banking; we are NOT a banking app, banking is IMO
+ confusing. Settings icon could be on top left, then
+ it would be more uniform, I would get rid of banking
+ 'tab' entirely!
+* iOS (text): bad icon for "pending outgoing", the
+ "minus" sign does not give me good associations here
+* Android (text): Title should be *Balances* (plural)
+* Android (minor): No "add" and "Send $CURRENCY" buttons
+ on this page.
+
+
+
+Adoption
+^^^^^^^^
+
+* iOS: transaction history visualization with red/green
+ bars after currency is nice.
+
+
+Actions
+^^^^^^^
+
+* **View transactions**. Clicking on a balance item should take you to the
+ transaction list (:ref:`cta-transaction-list-ref`) associated with that balance.
+
+Screenshots
+^^^^^^^^^^^
+
++-----------+------------------------------------------------------------------------+
+| Platform | Screenshot |
++===========+========================================================================+
+| WebEx | .. image:: ../screenshots/cta-balance-list-firefox-latest.png |
++-----------+------------------------------------------------------------------------+
+| Android | .. image:: ../screenshots/cta-balance-list-android-latest.png |
+| | :width: 30% |
++-----------+------------------------------------------------------------------------+
+| iOS | .. image:: wallet-screenshots/ios-wallet/11-balances-list-latest.png |
+| | :width: 30% |
++-----------+------------------------------------------------------------------------+
+
+
+.. _cta-transaction-list-ref:
+
+transaction-list
+----------------
+
+This screen shows a list of all the transactions associated with a given
+currency scope.
+
+Info
+^^^^
+
+* Total amount and currency (see :doc:`051-fractional-digits`).
+* List of transactions associated with the currency scope, with pending
+ transactions on top, and where each item contains the following:
+
+ * **Title**. It depends on the transaction type. It can be the exchange URL
+ (e.g. exchange.demo.taler.net) for withdraw,
+ the receiver name from the payto-URI for
+ deposits,
+ the human-provided summary of the transaction
+ (for push- and pull- P2P payments),
+ the name of the merchant paid
+ (e.g. Essay Shop) for payments to merchants and
+ refunds
+ * **Status**. It provides complementary information about the transaction
+ for the user, such as the status of the transaction (e.g. “Waiting for
+ confirmation,” “KYC required,” an error message, etc.). (The summary is
+ provided by wallet-core, along with internationalized versions.)
+ * **Timestamp**. The moment when the transaction was created. Ideally, it
+ should be shown with minimal precision, only showing the minutes, hours or
+ days that have elapsed.
+ * **Amount**. The positive or negative impact that the transaction has in
+ the total balance of the currency scope. It should be made clear whether
+ the amount of the transaction is positive or negative, ideally with a sign
+ (+/-) and a color (green/red).
+ * **Pending**. It should be indicated whether the transaction is pending or
+ finished. This can be done with a small badge and with different colors,
+ however, it should be always clear and communicate the message
+ effectively.
+
+Actions
+^^^^^^^
+
+* **Send**. The transaction list should include a button that allows the user
+ to initiate transactions that result in money being sent, such as deposits
+ and peer push payments.
+* **Receive**. The transaction list should also include a button that allows
+ the user to initiate transactions that result in money being received, such
+ as withdrawals and peer pull payments.
+* **View transaction details**. When clicking on a transaction, the user
+ should be taken to its corresponding transaction details depending on the
+ type of the transaction clicked.
+* **Select transaction(s)**. The user should be able to select one or more
+ transactions to perform specific bulk actions, such as deleting. The
+ interaction that triggers this action might differ across platforms. For
+ example, in Android this would be achieved by double pressing a transaction
+ (to activate selection mode) and then clicking other transactions to be
+ selected. On iOS, this could be achieved using an “Edit” button in the
+ toolbar that reveals checkboxes that allow the user to select the desired
+ transactions.
+* **Delete transaction(s)**. This could be achieved in bulk via selection
+ mode, or individually for each transaction via a menu or a button. Either
+ way, performing a deletion should always show a confirmation menu before
+ doing the actual deletion.
+
+Layout
+^^^^^^
+
+* The specific currency for which transactions are shown
+ SHOULD be prominent (title bar, menu bar)
+* The current balance should be on top (ideally always on-top)
+ just below the title and on the right of the "send" and "receive"
+ buttons. The current balance should align with the amounts
+ of the various transactions below. If possible, it should
+ have a label "Balance" near (ideally above) it.
+* There needs to be a way to go "back" to the
+ balance list (:ref:`cta-balance-list-ref`) **if**
+ we have more than a single currency in use. This
+ can be some (optional) "back" button or some
+ "home" button or some "balances" menu entry.
+* There should be a menu or button from where the QR code entry / scan
+ functionality is reachable (:ref:`cta-url-entry-ref`)
+* There COULD be a menu or button from where the settings screen (:ref:`cta-settings-ref`)
+ is reachable. The settings screen MUST be reachable
+ **if** there is no way to get to the balance list screen
+ because we only have a single currency.
+* In developer mode, there MAY be a menu or button
+ from where the developer tools (:ref:`cta-devtools-ref`)
+ are reachable. Alternatively, developer tools COULD
+ also only be reachable via settings.
+
+
+Issues
+^^^^^^
+
+* WebEx (text): Iconography (T), (W) is not as
+ nice as iconography in on Android.
+* WebEx (text): The balance is not labeled as the balance.
+* WebEx (text): Button is labeled as "Add",
+ while above says to use "Receive" which is
+ a better dual with "Send".
+* WebEx (image): Screenshot does not show any
+ pending transactions.
+* WebEx (nit): Android has different order of
+ items on top (send+receive, then balance).
+ This places the balance on top of the other
+ amounts, which is nicer.
+* Android (text): Iconography (same icon for push
+ payments and debit and POS) and again same icon
+ for invoice and withdraw) is sub-optimal. Should
+ pick unique icons for each type of operation.
+* Android (text): Button labels should just be
+ "Send" and "Receive" (without "funds").
+* iOS (text): Iconography (+ / -) is also not
+ expressive and redundant with the colors.
+* iOS (text): Sign of the operation (+ / -) should
+ be just before the amount (see Android), not
+ all the way on the left as an icon. Also can
+ probably be more subtle?
+* iOS (text): currency symbol in front of every
+ amount value is highly redundant; would be better
+ to list the currency once in the title (see Android)
+* iOS (minor): lacks search button (see Android)
+* all (text): use the merchant name for the main
+ transaction label on refunds (and payments to
+ merchants)
+* all (text): Use the human-provided *summary* of the
+ P2P payment for both push and pull payments (the
+ direction is clear from +/- on the amount, and
+ it should not matter who initiated!)
+* all (text): "Deposits" should use the receiver name
+ of the payto-URI of the target account (URL-decoded)
+ in the main title, instead of "Deposit"
+* iOS (text): "Withdrawal" shown instead of
+ exchange URL for withdraw
+* iOS (text): "Sent Requested money" shown instead of
+ exchange URL for withdraw
+* iOS (major): The balance is not shown. The
+ "send" and "receive" buttons are missing.
+* WebEx (minor): lacks search button (see Android)
+* iOS (minor): has top/buttom scroll buttons not present
+ in other UIs (likely too much, better to have search!)
+* WebEx (minor): unclear how to do bulk-deletion;
+ other platforms make it easy to select multiple
+ rows. Maybe have some checkboxes and then a
+ "delete selected" button at the bottom?
+* iOS (critical): the buttons to send/receive funds
+ are not even shown in the screenshot, likely because
+ of balances vs. banking distinction, which should
+ also be removed.
+* All (critical): we do not seem to have
+ screenshots of what happens after picking
+ select funds or receive funds!
+
+
+Adoption
+^^^^^^^^
+
+
+
+Screenshots
+^^^^^^^^^^^
+
++-----------+--------------------------------------------------------------------+
+| Platform | Screenshot |
++===========+====================================================================+
+| WebEx | .. image:: ../screenshots/cta-transaction-list-firefox-latest.png |
++-----------+--------------------------------------------------------------------+
+| Android | .. image:: ../screenshots/cta-transaction-list-android-latest.png |
+| | :width: 30% |
++-----------+--------------------------------------------------------------------+
+| iOS | .. image:: ../screenshots/cta-transaction-list-ios-latest.png |
+| | :width: 30% |
++-----------+--------------------------------------------------------------------+
+
+
+.. _cta-withdraw-review-ref:
+
+cta-withdraw-review
+-------------------
+
+This screen is used to inform the user that before they can proceed
+with a withdrawal, they must accept the terms of service of the exchange.
+
+
+Info
+^^^^
+
+* service provider to be used showing the URL
+* amount to be withdrawn
+* applicable fees (if any)
+
+* Text:
+
+ * Use "payment service provider" to label the
+ URL, not "exchange"
+ * Use "Net" and "Fees" and "Gross" to label
+ the amount in a section "Details"
+
+Inputs
+^^^^^^
+
+* service provider: allow the selection of different exchange (if applicable)
+
+
+Actions
+^^^^^^^
+
+* **change service provider**: updates fees shown (after returning from exchange selection screen)
+* **review and confirm ToS**: advance to the :ref:`cta-accept-tos-ref` screen
+* **back**: user will be redirected to previous screen
+
+.. attention::
+ User should be able to play with the amount, not possible in the current design
+
+Issues
+^^^^^^
+
+* All(critical): This is an extremely lazy screen,
+ and it probably should be completely revamped.
+ We should allow the user to change the exchange
+ **and** to enter the amount to withdraw
+ **unless** a fixed amount (or exchange) were
+ given when we were triggered.
+ Editing the exchange should go to another screen
+ (for now, with a simple URL entry bar, in the
+ future with exchange comparisson and whatever);
+ the fees should already be shown on this screen
+ for the selected exchange.
+* All(critical): We should probably unify this screen
+ with cta-withdraw-confirm and cta-withdraw,
+ with the only difference
+ being that one variant has "View Terms of Service"
+ while the other has a "Withdraw $AMOUNT" button.
+* iOS(image): no screenshot available
+* All(text): Use "Net" and "Fees" and "Gross" to label
+ the amounts in a section "Details"
+
+
+Screenshots
+^^^^^^^^^^^
+
++-----------+-----------------------------------------------------------------+
+| Platform | Screenshot |
++===========+=================================================================+
+| WebEx | .. image:: ../screenshots/cta-withdraw-review-chrome-latest.png |
++-----------+-----------------------------------------------------------------+
+| Android | .. image:: ../screenshots/cta-withdraw-review-android-latest.png|
+| | :width: 30% |
++-----------+-----------------------------------------------------------------+
+
+
+
+
+.. _cta-withdraw-ref:
+
+cta-withdraw
+------------
+
+This screen is used for the confirmation of a manual withdrawal,
+bank-integrated witdrawals and exchange withdrawals. the success of this
+operation will be an increase of the balance in the wallet. fee, restrictions
+and ETA should be clear for the user.
+
+Info
+^^^^
+
+* exchange to be used showing the URL
+* table of details of the operation: use the :ref:`operation-table-details-ref` screen
+* starting currency: if the exchange has the currency conversion service enabled user should be able to the details based on the wire transfer currency
+* taler URI: show copy button or QR to complete the operation with another device
+
+Inputs
+^^^^^^
+
+* age restriction: allow the selection of the restriction in the age group possible by the exchange
+* service provider: allow the selection of different exchange
+
+Actions
+^^^^^^^
+
+* **confirm operation**: on success will be redirected to the ``transaction-details`` screen where the detail of the current transaction will be displayed
+* **review and confirm ToS**: if the current selected exchange has a version of ToS that the user didn't yet accepted, use the :ref:`cta-accept-tos-ref` screen
+* **cancel**: user will be redirected to ``balance``
+
+.. attention::
+ User should be able to play with the amount, not possible in the current design
+
+Issues
+^^^^^^
+
+* All(screenshots): the flow here diverges completely betwen the different platforms (very bad).
+* Android(major): there really should not be a "check fees" button here, the fees should just be dynamically calculated and shown immediately. Note that the dialog shown here is thus closer to what we might make the future main
+ withdraw review (:ref:`cta-withdraw-review-ref`) dialog.
+
+
+Adoption
+^^^^^^^^
+
+* We should probably keep the "specify the origin
+ of the money" from Firefox as a dialog after
+ "Receive funds" is selected in the
+ transaction list (:ref:`cta-transaction-list-ref`),
+ but without the amount entry. Keep it simple,
+ mostly binary choice: withdraw, invoice, or back.
+* The iOS dialog is reasonably close to the future
+ withdraw review (:ref:`cta-withdraw-review-ref`) dialog,
+ allowing amount entry, shows fees, and final "confirm"
+ button (I guess: "review ToS" should be an alternative
+ button label). Eventually, we'll want an "edit" (pen)
+ icon next to the exchange URL, and
+ if context has fixed the amount or exchange, the
+ respective buttons should be hidden.
+
+
+Screenshots
+^^^^^^^^^^^
+
++-----------+----------------------------------------------------------------+
+| Platform | Screenshot |
++===========+================================================================+
+| WebEx | .. image:: ../screenshots/cta-withdraw-firefox-latest.png |
++-----------+----------------------------------------------------------------+
+| Android | .. image:: ../screenshots/cta-withdraw-android-latest.png |
+| | :width: 30% |
++-----------+----------------------------------------------------------------+
+| iOS | .. image:: ../screenshots/cta-withdraw-ios-latest.png |
+| | :width: 30% |
++-----------+----------------------------------------------------------------+
+
+
+.. _cta-withdraw-confirm-ref:
+
+cta-withdraw-confirm
+--------------------
+
+This screen is used to ask the the user to confirm the withdrawal operation,
+now that all data has been provided.
+
+
+Info
+^^^^
+
+* service provider to be used showing the URL
+* amount to be withdrawn
+* applicable fees (if any)
+
+Inputs
+^^^^^^
+
+* none?
+
+
+Actions
+^^^^^^^
+
+* **confirm withdraw**: advances to next screen
+* **back**: user will be redirected to previous screen
+
+Issues
+^^^^^^
+
+* All: This dialog should be merged with
+ the future main
+ withdraw review (:ref:`cta-withdraw-review-ref`) dialog
+ where the amount and exchange could be edited (if
+ permitted by trigger event) and the fees are dynamically
+ shown. No point in yet another dialog.
+
+
+Screenshots
+^^^^^^^^^^^
+
++-----------+------------------------------------------------------------------+
+| Platform | Screenshot |
++===========+==================================================================+
+| WebEx | .. image:: ../screenshots/cta-withdraw-confirm-firefox-latest.png|
++-----------+------------------------------------------------------------------+
+| Android | .. image:: ../screenshots/cta-withdraw-confirm-android-latest.png|
+| | :width: 30% |
++-----------+------------------------------------------------------------------+
+
+
+
+
+.. _cta-wire-transfer-ref:
+
+cta-wire-transfer
+-----------------
+
+This screen is used to show the user the information for the wire transfer to
+complete a manual withdrawal operation.
+
+Info
+^^^^
+
+* wire transfer subject to be used (first, most important)
+* target bank account to transfer funds to (e.g. IBAN)
+* total amount to transfer in the wire transfer currency
+* button to copy ``payto://`` URI with the information to clipboard
+
+Actions
+^^^^^^^
+
+* **abort**: aborts the withdrawal operation
+* **menu**: go back to the main balances list (operation continues in background)
+* **automatic**: screen changes to "cta-withdraw-done" upon completion
+
+Issues
+^^^^^^
+
+* WebEx(text): wire transfer subject is last, should be first!
+* WebEx(text): Receiver name is not shown (except within payto URI); must be shown above IBAN!
+ and only a link shown (see iOS)
+* WebEx(text): PaytoURI should not be expanded on-screen
+ and only a link shown (see iOS)
+* All(text): if there is no fee, no point in showing
+ the amount **3** times. Maybe only show the amount
+ on top with the wire transfer details, and then at
+ the bottom show the fee ONCE *if* there is one?
+* Android(text): uses "exchange", which is verboten
+* iOS(text): receiver name is missing, MUST be before IBAN
+* Android(text): wire transfer subject is third, should be first
+* WebEx(screenshot): the screenshot does not show how to select an alternative bank (see: Netzbon). Would be nice to show that.
+* Android(screenshot): the screenshot does not show how to select an alternative bank (see: Netzbon). Would be nice to show that.
+
+
+
+Adoption
+^^^^^^^^
+
+* WebEx/Android(text): Probably best to take the full text of the 3 steps from iOS (but add receiver name in step 2!) to provide very precise instructions.
+* WebEx/Android(text): "Open in banking app" is likely unclear that this requires Payto://-support. Use the long text from iOS everywhere!
+* iOS(minor): the way to switch between different banks is not as clear as it was on WebEx. Proposal: use notebook tabs similar to how it is done on WebEx (IIRC?)
+* Android: transaction status is not shown ("pending" on all other platforms. This is actually *good*, as once we are no longer "pending" the wire transfer details will no longer be shown, so the entire screen will look different. So we can probably get rid of the "This transaction is not complete" and "Status: Pending" on WebEx/iOS as that is *always* the case when we give the user wire transfer instructions here!
+
+
+
+Screenshots
+^^^^^^^^^^^
+
++-----------+------------------------------------------------------------------+
+| Platform | Screenshot |
++===========+==================================================================+
+| WebEx | .. image:: ../screenshots/cta-wire-transfer-firefox-latest.png |
++-----------+------------------------------------------------------------------+
+| Android | .. image:: ../screenshots/cta-wire-transfer-android-latest.png |
+| | :width: 30% |
++-----------+------------------------------------------------------------------+
+| iOS | .. image:: ../screenshots/cta-wire-transfer-ios-latest.png |
+| | :width: 30% |
++-----------+------------------------------------------------------------------+
+
+
+.. _cta-withdraw-done-ref:
+
+cta-withdraw-done
+-----------------
+
+This screen is used to show the user the information for a completed withdraw
+operation (bank-integrated or manual).
+
+Info
+^^^^
+
+* amount wired (hidden if no fees)
+* fees paid (hidden if no fees)
+* total amount withdrawn into wallet (effective balance change)
+* exchange base URL
+* date
+
+Actions
+^^^^^^^
+
+* **delete**: deletes information about the withdrawal operation
+
+Issues
+^^^^^^
+
+* WebEx(text): not point in showing details if there are no fees.
+* iOS(text): not point in showing details if there are no fees.
+* Android(text): still talks about 'exchange'
+* Android(text): has the amount twice, useless without fees
+* iOS(text): status: Done is unnecessary, if we show this screen, it will always be 'done' (ok, theoretically in the middle of withdrawing, but the wire transfer will be done; but then maybe show 'incoming' but hide the status once really "done").
+* unclear: "Delete" vs. 'Delete from history" --- two
+ styles, two translations, gain?
+
+
+Adoption
+^^^^^^^^
+
+* We probably want to show a "pending" transaction if we
+ are still withdrawing (wire transfer did arrived, coins
+ are still being generated). That's a very brief time,
+ but we probably want to use a minor variation of this
+ dialog in that case. Not sure it needs to be quite
+ as prominent as on iOS though...
+
+
+
+Screenshots
+^^^^^^^^^^^
+
++-----------+------------------------------------------------------------------+
+| Platform | Screenshot |
++===========+==================================================================+
+| WebEx | .. image:: ../screenshots/cta-withdraw-done-firefox-latest.png |
++-----------+------------------------------------------------------------------+
+| Android | .. image:: ../screenshots/cta-withdraw-done-android-latest.png |
+| | :width: 30% |
++-----------+------------------------------------------------------------------+
+| iOS | .. image:: ../screenshots/cta-withdraw-done-ios-latest.png |
+| | :width: 30% |
++-----------+------------------------------------------------------------------+
+
+
+.. _cta-url-entry-ref:
+
+cta-url-entry
+-------------
+
+This screen allows the user to scan a QR code, scan an NFC tag, or enter a
+taler://-URL. Its implementation may differ significantly between
+platforms. For example, scanning NFC tags may be fully automated, scanning QR
+codes may involve some system applications, and maybe the dialog only allows
+the URL entry *or* the camera but not both at the same time, depending on
+implementation specifics.
+
+Info
+^^^^
+
+* camera with current image to enable user to focus on QR code
+* current URL, with information if it is not well-formed for GNU Taler
+* possibly status information on NFC reader (if available)
+
+Actions
+^^^^^^^
+
+* **open**: if entered manually, open URL as-entered (otherwise open is automatic)
+* **back**: return to previous view
+
+Issues
+^^^^^^
+
+* WebEx(text) has additional actions "clear" (not necessary, I can manually clear), "Read QR from file" (who does that!???!) that should be removed.
+* Android(text) has button label "OK", should probably be "Open" for uniformity.
+* Android(text) has "Enter Taler URI", while WebEx has clearer text "enter taler:// URI".
+* iOS (screenshot): lacks dialog (or screenshot?) entirely, not sure if we need manual URL-entry on mobile though, so could be OK!
+
+
+
+
+Screenshots
+^^^^^^^^^^^
+
++-----------+------------------------------------------------------------------+
+| Platform | Screenshot |
++===========+==================================================================+
+| WebEx | .. image:: ../screenshots/cta-url-entry-firefox-latest.png |
++-----------+------------------------------------------------------------------+
+| Android | .. image:: ../screenshots/cta-url-entry-android-latest.png |
+| | :width: 30% |
++-----------+------------------------------------------------------------------+
+
+
+.. _cta-payment-ref:
+
+cta-payment
+-----------
+
+This screen is used for the confirmation of a payment to a merchant. the
+success of this operation will be an decrease of the balance in the wallet and
+save a ticket/invoice of the purchase. fee, restrictions and ETA should be
+clear for the user.
+
+Info
+^^^^
+
+* merchant offering the order showing the URL
+* order summary
+* table of details of the operation: use the :ref:`operation-table-details-ref` screen
+* receipt: order id
+* payment deadline: absolute time before the claimed order expires
+* taler URI: show copy button or QR to complete the operation with another device
+* cant pay desc: if the user has enough balance but unable to use it
+* payment status: if the
+
+Actions
+^^^^^^^
+
+* **confirm operation**: if the payment is possible, on success will be redirected to the ``transaction-details`` screen where the detail of the current transaction will be displayed
+* **get more cash**: if there is not enough balance, it will be redirected to :ref:`cta-withdraw-ref`
+* **cancel**: user will be redirected to ``balance``
+
+Issues
+^^^^^^
+
+* WebEx(Text): showing price/total without fees is a bit excessive, could be simplified in absence of fees
+* WebEx(Text): "Valid until" is likely confusing, not shown on other platforms. Maybe only show "offer expired" instead of pay button (on all platforms!)?
+* WebEx(Text): Receipt number is not shown on other platforms at this time, which also makes sense as it is only an order number and certainly nothing like a receipt before payment! (Remove!)
+* WebEx(Screenshot): would be good to show the dialog with expanded order details as well, maybe even expand by default like on Android (and forgo the button?)
+* WebEx(Screenshot): would be good to show a version of the dialog with fees in the screenshot.
+* iOS(text): the label 'Summary' appears only on iOS, and seems unnecessary. Especially since no long-form is available anywhere.
+* All(screenshot): would be good to have sceenshots of the main variations: with/without product preview images, with/without fees, full details/partial details (if we have such a toggle).
+
+
+Screenshots
+^^^^^^^^^^^
+
++-----------+------------------------------------------------------------------+
+| Platform | Screenshot |
++===========+==================================================================+
+| WebEx | .. image:: ../screenshots/cta-payment-firefox-latest.png |
++-----------+------------------------------------------------------------------+
+| Android | .. image:: ../screenshots/cta-payment-android-latest.png |
+| | :width: 30% |
++-----------+------------------------------------------------------------------+
+| iOS | .. image:: ../screenshots/cta-payment-ios-latest.png |
+| | :width: 30% |
++-----------+------------------------------------------------------------------+
+
+
+.. _cta-payment-paid-ref:
+
+cta-payment-paid
+----------------
+
+This screen is used to show information with details about a historic payment.
+
+Info
+^^^^
+
+* merchant offering the order showing the URL
+* order summary
+* table of details of the operation: use the :ref:`operation-table-details-ref` screen
+* receipt: order id
+* payment status: if the order was refunded
+* Text to use:
+
+ * **Title**. Name of the merchant paid
+ (e.g. Essay Shop)
+ * **Status**. It provides complementary information about the transaction
+ for the user, such as the status of the transaction (e.g. “Waiting for
+ confirmation,” “KYC required,” an error message, etc.). (The summary is
+ provided by wallet-core, along with internationalized versions.)
+ * **Timestamp**. The moment when the payment was made. Ideally, it
+ should be shown with minimal precision, only showing the minutes, hours or
+ days that have elapsed.
+ * **Amount**. The negative impact that the transaction has in
+ the total balance of the currency scope. It should be made clear that the amount is negative, ideally with a sign (-) and a color (red).
+
+
+Actions
+^^^^^^^
+
+* **delete**: delete information about the transaction
+* **back**: user will be redirected to ``balance``
+
+Issues
+^^^^^^
+
+* WebEx(text): Details should be simplified if there are no fees
+* Android(text): details say receipt, but WebEx uses the slightly more accurate "Invoice ID". Could also use "Order #"?
+* iOS(major): delete button is missing, instead only has "Done"
+
+
+
+Screenshots
+^^^^^^^^^^^
+
++-----------+------------------------------------------------------------------+
+| Platform | Screenshot |
++===========+==================================================================+
+| WebEx | .. image:: ../screenshots/cta-payment-paid-firefox-latest.png |
++-----------+------------------------------------------------------------------+
+| Android | .. image:: ../screenshots/cta-payment-paid-android-latest.png |
+| | :width: 30% |
++-----------+------------------------------------------------------------------+
+| iOS | .. image:: ../screenshots/cta-payment-paid-ios-latest.png |
+| | :width: 30% |
++-----------+------------------------------------------------------------------+
+
+
+.. _cta-deposit-ref:
+
+cta-deposit
+------------
+
+This screen is used for the confirmation of a deposit. the success of this
+operation will be an decrease of the balance in the wallet and save a deposit
+ticket for reference. fee, restrictions and ETA should be clear for the user.
+
+Info
+^^^^
+
+* bank account where the money is going to
+* table of details of the operation: use the :ref:`operation-table-details-ref` screen
+
+Actions
+^^^^^^^
+
+* **confirm operation**: on success will be redirected to the ``transaction-details`` screen where the detail of the current transaction will be displayed
+* **cancel**: user will be redirected to ``balance``
+
+.. attention::
+ User should be able to play with the amount, not possible in the current design
+
+Issues
+^^^^^^
+
+* WebEx(screenshot): need new section in this document for 'ctx-manage-account'.
+* WebEx(minor): should probably separate out target account selection and amount entry, as done on iOS
+* WebEx(text): "amount" is a bad label, "brut amount" might be good, then use "net deposit"
+* WebEx(text): might be good to have "net deposit" amount also editable, not just computed (and then update "brut amount").
+* Android(screenshot): lacks screenshots for dialogs where we enter/edit accounts and amounts
+* Android(minor): if we do it iOS/WebEx style, we can probalby skip the 'pure' confirmation dialog and have the one where the brut/net amounts are entered be the final one in the sequence before the transaction happens
+* all(screenshot): we need a new dialog showing the transaction in-flight/done as reachable via transaction history
+
+
+Adoption
+^^^^^^^^
+
+* iOS: I think it makes sense to split this section up into account selection / management and amount entry & confirmation; we should only have one major screen per section! Please split other UIs similarly and let's introduce a new section here.
+
+
+
+
+
+Screenshots
+^^^^^^^^^^^
+
++-----------+------------------------------------------------------------------+
+| Platform | Screenshot |
++===========+==================================================================+
+| WebEx | .. image:: ../screenshots/cta-deposit-firefox-latest.png |
++-----------+------------------------------------------------------------------+
+| Android | .. image:: ../screenshots/cta-deposit-android-latest.png |
+| | :width: 30% |
++-----------+------------------------------------------------------------------+
+| iOS | .. image:: ../screenshots/cta-deposit-1-ios-latest.png |
+| | :width: 30% |
+| | .. image:: ../screenshots/cta-deposit-2-ios-latest.png |
+| | :width: 30% |
++-----------+------------------------------------------------------------------+
+
+
+.. _cta-peer-pull-initiate-ref:
+
+cta-peer-pull-initiate
+----------------------
+
+This screen is used for the confirmation of the creation of a peer pull
+transaction or invoice to request money from another wallet. the success of
+this operation will not change the balance immediately in the wallet and allow
+the user to share a taler URI to the payer. fee, restrictions and ETA should
+be clear for the user.
+
+Info
+^^^^
+
+* exchange to be used showing the URL
+* table of details of the operation: use the :ref:`operation-table-details-ref` screen
+
+Inputs
+^^^^^^
+
+* **subject**: short description of the transaction
+* **expiration**: absolute time/date after which the invoice is not valid anymore
+* **service provider**: allow the selection of different exchange
+
+Actions
+^^^^^^^
+
+* **confirm operation**: on success will be redirected to the ``transaction-details`` screen where the detail of the current transaction will be displayed
+* **review and confirm ToS**: if the current selected exchange has a version of ToS that the user didn't yet accepted, use the :ref:`cta-accept-tos-ref` screen
+* *cancel*: user will be redirected to ``balance``
+
+.. attention::
+ Is the invoice creation always free of charge or does the exchange have a mechanism
+ to impose a fee to pay on creation?
+
+Issues
+^^^^^^
+
+* WebEx(text): 20 days is odd, Android has 30 days instead
+* Android(text): Webex uses "1 Week" instead of "7 days", let's use "week".
+* iOS(text): 3 min/ 1h are inconsistent; other wallets have 1 day, 7 days, 30 days. We should be consistent.
+
+
+Adoption
+^^^^^^^^
+
+Screenshots
+^^^^^^^^^^^
+
++-----------+----------------------------------------------------------------------+
+| Platform | Screenshot |
++===========+======================================================================+
+| WebEx | .. image:: ../screenshots/cta-peer-pull-initiate-firefox-latest.png |
++-----------+----------------------------------------------------------------------+
+| Android | .. image:: ../screenshots/cta-peer-pull-initiate-android-latest.png |
+| | :width: 30% |
++-----------+----------------------------------------------------------------------+
+| iOS | .. image:: ../screenshots/cta-peer-pull-initiate-ios-latest.png |
+| | :width: 30% |
++-----------+----------------------------------------------------------------------+
+
+
+.. _cta-peer-pull-confirm-ref:
+
+cta-peer-pull-confirm
+---------------------
+
+This screen is used for the confirmation of the payment of a peer pull
+transaction or invoice to send money from another wallet. the success of this
+operation will be an will decrease the balance in the wallet. fee,
+restrictions and ETA should be clear for the user.
+
+Info
+^^^^
+
+* exchange to be used showing the URL
+* subject: short description of the transaction
+* table of details of the operation: use the :ref:`operation-table-details-ref` screen
+* expiration: absolute time/date after which the invoice is not valid anymore
+
+Actions
+^^^^^^^
+
+* **confirm operation**: if the payment is possible, on success will be redirected to the ``transaction-details`` screen where the detail of the current transaction will be displayed
+* **get more cash**: if there is not enough balance, it will be redirected to :ref:`cta-withdraw-ref`
+* **cancel**: user will be redirected to ``balance``
+
+cta-peer-push-initiate
+----------------------
+
+This screen is used for the confirmation of the creation of a peer push
+transaction or transfer money to another wallet. the success of this
+operation will reduce the balance immediately in the wallet and allow the user
+to share a taler URI to the receiver. fee, restrictions and ETA should be
+clear for the user.
+
+Info
+^^^^
+
+* table of details of the operation: use the ``operation-table-details`` screen
+
+Inputs
+^^^^^^
+
+* **subject**: short description of the transaction
+* **expiration**: absolute time/date after which the transfer is not valid anymore
+
+Actions
+^^^^^^^
+
+* **confirm operation**: on success will be redirected to the ``transaction-details`` screen where the detail of the current transaction will be displayed
+* **cancel**: user will be redirected to ``balance``
+
+Issues
+^^^^^^
+
+* WebEx(minor): forces user to scroll to the bottom. Android nicely shows the accept button always; that seems nicer;
+* WebEx(text): has text about "Digital cash withdrawal" above. Would be more consistent if we also *only* showed the Terms of service.
+* Android(text): uses "Exchange", should say "PSP's Terms of Service"
+* iOS(screenshot): lacks actual ToS, not ideal to compare!
+
+
+Adoption
+^^^^^^^^
+
+
+Screenshots
+^^^^^^^^^^^
+
++-----------+----------------------------------------------------------------------+
+| Platform | Screenshot |
++===========+======================================================================+
+| WebEx | .. image:: ../screenshots/cta-peer-push-initiate-firefox-latest.png |
++-----------+----------------------------------------------------------------------+
+| Android | .. image:: ../screenshots/cta-peer-push-initiate-android-latest.png |
+| | :width: 30% |
++-----------+----------------------------------------------------------------------+
+| iOS | .. image:: ../screenshots/cta-peer-push-initiate-ios-latest.png |
+| | :width: 30% |
++-----------+----------------------------------------------------------------------+
+
+
+.. _cta-peer-push-confirm-ref:
+
+cta-peer-push-confirm
+---------------------
+
+This screen is used for the confirmation of the acceptance of a peer push
+transaction or transfer money to this wallet. the success of this operation
+will be an will decrease the balance in the wallet. fee, restrictions and ETA
+should be clear for the user.
+
+Info
+^^^^
+
+* subject: short description of the payment
+* expiration: absolute time/date after which the invoice is not valid anymore
+* table of details of the operation: use the ``operation-table-details`` screen
+
+Actions
+^^^^^^^
+
+* **confirm operation**: on success will be redirected to the ``transaction-details`` screen where the detail of the current transaction will be displayed
+* **review and confirm ToS**: if the current selected exchange has a version of ToS that the user didn't yet accepted, use the :ref:`cta-accept-tos-ref` screen
+* **cancel**: user will be redirected to ``balance``
+
+Issues
+^^^^^^
+
+* All(screenshot): we have no screenshots!
+
+
+Adoption
+^^^^^^^^
+
+
+Screenshots
+^^^^^^^^^^^
+
+
+.. _operation-table-details-ref:
+
+operation-table-details
+-----------------------
+
+With the table it should be clear how much the operation will cost, the
+initial amount and the final amount with all the items related to the
+operations (like fee)
+
+Labels
+^^^^^^
+
+Initial amount of the operation, and final amount are always shown. Fee should
+be shown as an extra row in the table if it is non-zero. Converted amount
+should be shown as an extra row if initial amount currency is not the same as
+the final amount currency.
+
+Initial amount label by operation:
+
+ * payment -> Price
+ * deposit -> Send
+ * peer-pull-credit -> Invoice
+ * peer-pull-debit -> Invoice
+ * peer-push-debit -> Send
+ * peer-push-credit -> Transfer
+ * withdrawal -> Transfer
+ * refund -> Refund
+
+
+.. _cta-accept-tos-ref:
+
+accept-tos
+----------
+
+This screen can be use everytime that the user is going to interact with an
+exchange. since at any moment wallet may find that ToS changed the user needs
+to be prevented from continue before reading/accepting new rules. If possible,
+this screen should be used inplace of other actions and hidden if not required
+(for example, user already accepted ToS)
+
+Inputs
+^^^^^^
+
+* **format**: allow the selection of a ToS format
+* **languange**: allow the selection of a languange different from system lang
+
+Actions
+^^^^^^^
+
+* **accept tos**: will mark this version as accepted in wallet core and redirect the user to the screen from where it was invoked
+* **save/print tos**: will save the ToS outside of the wallet
+
+Issues
+^^^^^^
+
+
+
+Adoption
+^^^^^^^^
+
+
+Screenshots
+^^^^^^^^^^^
+
++-----------+------------------------------------------------------------------+
+| Platform | Screenshot |
++===========+==================================================================+
+| WebEx | .. image:: ../screenshots/cta-accept-tos-firefox-latest.png |
+| | :width: 30% |
++-----------+------------------------------------------------------------------+
+| Android | .. image:: ../screenshots/cta-accept-tos-android-latest.png |
+| | :width: 30% |
++-----------+------------------------------------------------------------------+
+| iOS | .. image:: ../screenshots/cta-accept-tos-ios-latest.png |
+| | :width: 30% |
++-----------+------------------------------------------------------------------+
+
+.. _cta-settings-ref:
+
+settings
+--------
+
+Info
+^^^^
+
+Layout
+^^^^^^
+
+Actions
+^^^^^^^
+
+Issues
+^^^^^^
+
+Adoption
+^^^^^^^^
+
+Screenshots
+^^^^^^^^^^^
+
+
+.. _cta-devtools-ref:
+
+developer-tools
+---------------
+
+Info
+^^^^
+
+Layout
+^^^^^^
+
+Actions
+^^^^^^^
+
+Issues
+^^^^^^
+
+Adoption
+^^^^^^^^
+
+Screenshots
+^^^^^^^^^^^
+
+
+
+
+
+Q / A
+=====
diff --git a/design-documents/054-dynamic-form.rst b/design-documents/054-dynamic-form.rst
new file mode 100644
index 00000000..d93b3684
--- /dev/null
+++ b/design-documents/054-dynamic-form.rst
@@ -0,0 +1,201 @@
+DD 54: Dynamic Web Form
+#######################
+
+Summary
+=======
+
+This document outlines the approach for implementing a dynamic web form feature.
+
+Motivation
+==========
+
+Currently, creating a new form for a web app involves coding a new
+page with HTML, CSS, and JS. Exchange AML requires multiple forms,
+and different instances may have distinct forms based on jurisdiction.
+
+
+Requirements
+============
+
+A form consist of a layout and a set of fields.
+
+Layout requirements
+-------------------
+
+* **editable by system admin**: System admins should be able to create new forms
+ or edit current one shipped with the source.
+
+* **accesibility**: Forms should meet accessibility level AA.
+
+* **responsive**: Forms should be responsive and function on all devices.
+
+* **metadata**: Generated form information should contain enough data
+ to handle multiple form versions.
+
+Fields requirements
+-------------------
+
+* **validations**: Each field may require custom validation
+
+* **custom data type**: A field may consist of a list, string, number, or a
+ complex composite structure.
+
+
+Proposed Solutions
+==================
+
+Forms are initialized using a flexible structure defined by the
+TypeScript interface FormType<T>. This interface comprises properties
+such as value (current form data), initial (initial form data for resetting),
+readOnly (flag to disable input), onUpdate (callback on form data update),
+and computeFormState (function to derive the form state based on current data).
+
+
+.. code-block:: typescript
+
+ interface FormType<T extends object> {
+ value: Partial<T>;
+ initial?: Partial<T>;
+ readOnly?: boolean;
+ onUpdate?: (v: Partial<T>) => void;
+ computeFormState?: (v: Partial<T>) => FormState<T>;
+ }
+
+
+``T``: is the type of the result object
+``value``: is a reference to the current value of the result
+``initial``: data for resetting
+``readOnly``: when true, fields won't allow input
+``onUpdate``: notification of the result update
+``computeFormState``: compute a new state of the form based on the current value
+
+Form state have the same shape of ``T`` but every field type is ``FieldUIOptions``.
+
+Fields type can be:
+ * strings
+ * numbers
+ * boolean
+ * arrays
+ * object
+
+The field type ``AmountJson`` and ``AbsoluteTime`` are opaque since field is used as a whole.
+
+The form can be instanciated using
+
+.. code-block:: typescript
+
+ import { FormProvider } from "@gnu-taler/web-util/browser";
+
+
+Then the field component can access all the properties by the ``useField(name)`` hook,
+which will return
+
+.. code-block:: typescript
+
+ interface InputFieldHandler<Type> {
+ value: Type;
+ onChange: (s: Type) => void;
+ state: FieldUIOptions;
+ isDirty: boolean;
+ }
+
+
+``value``: the current value of the field
+``onChange``: a function to call anytime the user want to change the value
+``state``: the state of the field (hidden, error, etc..)
+``isDirty``: if the user already tried to change the value
+
+A set of common form field exist in ``@gnu-taler/web-util``:
+
+ * InputAbsoluteTime
+ * InputAmount
+ * InputArray
+ * InputFile
+ * InputText
+ * InputToggle
+
+and should be used inside a ``Form`` context.
+
+.. code-block:: none
+
+ function MyFormComponent():VNode {
+ return <FormProvider>
+ <InputAmount name="amount" />
+ <InputText name="subject" />
+ <button type="submit"> Confirm </button>
+ </FormProvider>
+ }
+
+
+Example
+--------
+
+Consider a form shape represented by the TypeScript type:
+
+.. code-block:: typescript
+
+ type TheFormType = {
+ name: string,
+ age: number,
+ savings: AmountJson,
+ nextBirthday: AbsoluteTime,
+ pets: string[],
+ addres: {
+ street: string,
+ city: string,
+ }
+ }
+
+An example instance of this form could be:
+
+.. code-block:: typescript
+
+ const theFormValue: TheFormType = {
+ name: "Sebastian",
+ age: 15,
+ pets: ["dog","cat"],
+ address: {
+ street: "long",
+ city: "big",
+ }
+ }
+
+
+For such a form, a valid state can be computed using a function like
+``computeFormStateBasedOnFormValues``, returning an object indicating
+the state of each field, including properties such as ``hidden``,
+``disabled``, and ``required``.
+
+
+.. code-block:: javascript
+
+ function computeFormStateBasedOnFormValues(formValues): {
+ //returning fixed state as an example
+ //the return state will be commonly be computed from the values of the form
+ return {
+ age: {
+ hidden: true,
+ },
+ pets: {
+ disabled: true,
+ elements: [{
+ disabled: false,
+ }],
+ },
+ address: {
+ street: {
+ required: true,
+ error: "the street name was not found",
+ },
+ city: {
+ required: true,
+ },
+ },
+ }
+ }
+
+
+
+
+Q / A
+=====
diff --git a/design-documents/055-wallet-problem-report.rst b/design-documents/055-wallet-problem-report.rst
new file mode 100644
index 00000000..2fd7a221
--- /dev/null
+++ b/design-documents/055-wallet-problem-report.rst
@@ -0,0 +1,114 @@
+DD 55: Wallet Problem Reports
+#############################
+
+.. note::
+
+ **Status**: Early work in progress / DD number reservation.
+
+.. warning::
+
+ We concluded that we don't need the problem reports feature right now,
+ as all cases we care about are already covered by something else.
+
+Summary
+=======
+
+This design document specifies global error reports generated/managed by wallet-core
+and rendered by the wallet UIs.
+
+Motivation
+==========
+
+Sometimes the wallet encounters issues that go beyond the scope of single transaction.
+
+Requirements
+============
+
+* problem reports must have a clear lifecycle
+* problem reports must have some type of identification that allows to
+ easily find out if a new problem report needs to be created when an
+ error happens or whether an existing one has been created
+
+Proposed Solution
+=================
+
+Report identification
+---------------------
+
+The report identifier serves multiple purposes:
+
+1. Usage as a reference in wallet-core APIs
+2. De-duplication. The report ID should allow easy identification of an already existing report for a particular problem.
+
+New wallet-core requests
+------------------------
+
+* ``listProblemReports``
+* ``acknowledgeProblemReport``: Mark a problem report as read.
+* ``deleteProblemReport``: Delete the problem report.
+
+New wallet-core notification type
+---------------------------------
+
+* ``problem-report`` to notify clients about status changes or an error report
+ (including creation!)
+
+
+Types of reports
+----------------
+
+(Currently we don't have any good examples where this is actually needed.)
+
+Examples of what should NOT be a report
+---------------------------------------
+
+* money lost due to the exchange stopping to offer a denomination
+
+ * => Should be a transactions item
+
+* money locked behind a (long) pending refresh
+
+ * => Should be a pending transaction
+
+* money lost due to a permanently failing refresh
+
+ * => pending or final transaction item
+
+* money lost due to expired denominations (auto-refresh wasn't done fast enough)
+
+ * => transaction item
+
+* a denomination changed its info (expiration, fees)
+
+ * => exchange entry state
+
+* Important information about the exchange changed (master pub, accounts, keys)
+
+ => exchange entry state
+
+
+Definition of Done
+==================
+
+TBD.
+
+Alternatives
+============
+
+* Report problems with an API specific to each resource (exchange entry, transaction, ...)
+* Have an *alerts* API that returns alerts to the client that the client can show to to the user,
+ but that a user can't interact with.
+
+Drawbacks
+=========
+
+TBD.
+
+Discussion / Q&A
+================
+
+* When is a report amended vs a new report created?
+
+ * example: Exchange stops offering denomination D1. Later, it stops offering D2.
+ Are two reports generated or is the first report changed?
+
diff --git a/design-documents/999-template.rst b/design-documents/999-template.rst
index f620248d..988f163f 100644
--- a/design-documents/999-template.rst
+++ b/design-documents/999-template.rst
@@ -1,5 +1,5 @@
-Template
-########
+DD XY: Template
+###############
Summary
=======
@@ -13,6 +13,13 @@ Requirements
Proposed Solution
=================
+Definition of Done
+==================
+
+(Only applicable to design documents that describe a new feature. While the
+DoD is not satisfied yet, a user-facing feature **must** be behind a feature
+flag or dev-mode flag.)
+
Alternatives
============
diff --git a/design-documents/_svgs/escrow-flow.svg b/design-documents/_svgs/escrow-flow.svg
new file mode 100644
index 00000000..6fc0a51f
--- /dev/null
+++ b/design-documents/_svgs/escrow-flow.svg
@@ -0,0 +1 @@
+<svg aria-labelledby="chart-title-graph-div chart-desc-graph-div" role="img" viewBox="-111 -10 1273 1070" style="max-width: 1273px;" height="1070" xmlns="http://www.w3.org/2000/svg" width="100%" id="graph-div"><title id="chart-title-graph-div"></title><desc id="chart-desc-graph-div"></desc><style>#graph-div {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#graph-div .error-icon{fill:#552222;}#graph-div .error-text{fill:#552222;stroke:#552222;}#graph-div .edge-thickness-normal{stroke-width:2px;}#graph-div .edge-thickness-thick{stroke-width:3.5px;}#graph-div .edge-pattern-solid{stroke-dasharray:0;}#graph-div .edge-pattern-dashed{stroke-dasharray:3;}#graph-div .edge-pattern-dotted{stroke-dasharray:2;}#graph-div .marker{fill:#333333;333;}#graph-div .marker.cross{333;}#graph-div svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#graph-div .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#graph-div text.actor&gt;tspan{fill:black;stroke:none;}#graph-div .actor-line{stroke:grey;}#graph-div .messageLine0{stroke-width:1.5;stroke-dasharray:none;;}#graph-div .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;;}#graph-div #arrowhead path{fill:#333;;}#graph-div .sequenceNumber{fill:white;}#graph-div #sequencenumber{fill:#333;}#graph-div #crosshead path{fill:#333;;}#graph-div .messageText{fill:#333;;}#graph-div .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#graph-div .labelText,#graph-div .labelText&gt;tspan{fill:black;stroke:none;}#graph-div .loopText,#graph-div .loopText&gt;tspan{fill:black;stroke:none;}#graph-div .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#graph-div .note{stroke:#aaaa33;fill:#fff5ad;}#graph-div .noteText,#graph-div .noteText&gt;tspan{fill:black;stroke:none;}#graph-div .activation0{fill:#f4f4f4;stroke:#666;}#graph-div .activation1{fill:#f4f4f4;stroke:#666;}#graph-div .activation2{fill:#f4f4f4;stroke:#666;}#graph-div .actorPopupMenu{position:absolute;}#graph-div .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#graph-div .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#graph-div .actor-man circle,#graph-div line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#graph-div :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g></g><defs><symbol height="24" width="24" id="computer"><path d="M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z" transform="scale(.5)"></path></symbol></defs><defs><symbol clip-rule="evenodd" fill-rule="evenodd" id="database"><path d="M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z" transform="scale(.5)"></path></symbol></defs><defs><symbol height="24" width="24" id="clock"><path d="M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z" transform="scale(.5)"></path></symbol></defs><g><line stroke="#999" stroke-width="0.5px" class="200" y2="1004" x2="75" y1="5" x1="75" id="actor6934"></line><g id="root-6934"><rect class="actor" ry="3" rx="3" height="65" width="150" stroke="#666" fill="#eaeaea" y="0" x="0"></rect><text style="text-anchor: middle; font-size: 14px; font-weight: 400; font-family: &quot;Open Sans&quot;, sans-serif;" class="actor" alignment-baseline="central" dominant-baseline="central" y="32.5" x="75"><tspan dy="0" x="75">Seller</tspan></text></g></g><g><line stroke="#999" stroke-width="0.5px" class="200" y2="1004" x2="575" y1="5" x1="575" id="actor6935"></line><g id="root-6935"><rect class="actor" ry="3" rx="3" height="65" width="150" stroke="#666" fill="#eaeaea" y="0" x="500"></rect><text style="text-anchor: middle; font-size: 14px; font-weight: 400; font-family: &quot;Open Sans&quot;, sans-serif;" class="actor" alignment-baseline="central" dominant-baseline="central" y="32.5" x="575"><tspan dy="0" x="575">Exchange</tspan></text></g></g><g><line stroke="#999" stroke-width="0.5px" class="200" y2="1004" x2="949" y1="5" x1="949" id="actor6936"></line><g id="root-6936"><rect class="actor" ry="3" rx="3" height="65" width="150" stroke="#666" fill="#eaeaea" y="0" x="874"></rect><text style="text-anchor: middle; font-size: 14px; font-weight: 400; font-family: &quot;Open Sans&quot;, sans-serif;" class="actor" alignment-baseline="central" dominant-baseline="central" y="32.5" x="949"><tspan dy="0" x="949">Buyer</tspan></text></g></g><defs><marker orient="auto" markerHeight="12" markerWidth="12" markerUnits="userSpaceOnUse" refY="5" refX="9" id="arrowhead"><path d="M 0 0 L 10 5 L 0 10 z"></path></marker></defs><defs><marker refY="4" refX="16" orient="auto" markerHeight="8" markerWidth="15" id="crosshead"><path style="stroke-dasharray: 0, 0;" d="M 9,2 V 6 L16,4 Z" stroke-width="1px" stroke="#000000" fill="black"></path><path style="stroke-dasharray: 0, 0;" d="M 0,1 L 6,7 M 6,1 L 0,7" stroke-width="1px" stroke="#000000" fill="none"></path></marker></defs><defs><marker orient="auto" markerHeight="28" markerWidth="20" refY="7" refX="18" id="filled-head"><path d="M 18,7 L9,13 L14,7 L9,1 Z"></path></marker></defs><defs><marker orient="auto" markerHeight="40" markerWidth="60" refY="15" refX="15" id="sequencenumber"><circle r="6" cy="15" cx="15"></circle></marker></defs><g><rect class="note" ry="0" rx="0" height="52" width="272" stroke="#666" fill="#EDF2AE" y="75" x="-61"></rect><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="80" x="75"><tspan x="75">The seller creates an escrow account </tspan></text><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="96" x="75"><tspan x="75"> with specific terms and a public key EID</tspan></text></g><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 16px; font-weight: 400;" dy="1em" class="messageText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="142" x="325">register escrow (EID, [m, M], starttime, endtime)</text><line style="fill: none;" marker-end="url(#arrowhead)" stroke="none" stroke-width="2" class="messageLine0" y2="175" x2="575" y1="175" x1="75"></line><g><rect class="activation0" ry="0" rx="0" height="48" width="10" stroke="#666" fill="#EDF2AE" y="175" x="570"></rect></g><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 16px; font-weight: 400;" dy="1em" class="messageText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="190" x="323">(EID + sig_e(EID, [m, M], starttime, endtime))</text><line style="fill: none;" marker-end="url(#arrowhead)" stroke="none" stroke-width="2" class="messageLine0" y2="223" x2="75" y1="223" x1="570"></line><g><rect class="note" ry="0" rx="0" height="52" width="188" stroke="#666" fill="#EDF2AE" y="233" x="-19"></rect><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="238" x="75"><tspan x="75">Seller publishes the EID, </tspan></text><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="254" x="75"><tspan x="75"> for example for an auction</tspan></text></g><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 16px; font-weight: 400;" dy="1em" class="messageText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="300" x="512">publish auction (EID, [m, M], starttime, endtime, sig)</text><line style="stroke-dasharray: 3, 3; fill: none;" marker-end="url(#arrowhead)" stroke="none" stroke-width="2" class="messageLine1" y2="333" x2="949" y1="333" x1="75"></line><g><rect class="note" ry="0" rx="0" height="53" width="326" stroke="#666" fill="#EDF2AE" y="343" x="786"></rect><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="348" x="949"><tspan x="949">An interested bidder can receive the list of</tspan></text><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="364" x="949"><tspan x="949"> depositors (not amounts) for the escrow account</tspan></text></g><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 16px; font-weight: 400;" dy="1em" class="messageText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="411" x="762">list(EID)</text><line style="fill: none;" marker-end="url(#arrowhead)" stroke="none" stroke-width="2" class="messageLine0" y2="444" x2="575" y1="444" x1="949"></line><g><rect class="activation0" ry="0" rx="0" height="48" width="10" stroke="#666" fill="#EDF2AE" y="444" x="570"></rect></g><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 16px; font-weight: 400;" dy="1em" class="messageText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="459" x="765">list of depositors</text><line style="fill: none;" marker-end="url(#arrowhead)" stroke="none" stroke-width="2" class="messageLine0" y2="492" x2="949" y1="492" x1="580"></line><g><rect class="note" ry="0" rx="0" height="52" width="315" stroke="#666" fill="#EDF2AE" y="502" x="791.5"></rect><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="507" x="949"><tspan x="949">A interested bidder can deposit coins into the </tspan></text><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="523" x="949"><tspan x="949">escrow account and receives a proof of escrow</tspan></text></g><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 16px; font-weight: 400;" dy="1em" class="messageText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="569" x="762">deposit(EID, amount, coins[], DEPOSIT_ID)</text><line style="fill: none;" marker-end="url(#arrowhead)" stroke="none" stroke-width="2" class="messageLine0" y2="602" x2="575" y1="602" x1="949"></line><g><rect class="activation0" ry="0" rx="0" height="48" width="10" stroke="#666" fill="#EDF2AE" y="602" x="570"></rect></g><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 16px; font-weight: 400;" dy="1em" class="messageText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="617" x="765">proof (EID, DEPOSIT_ID, [m,M])</text><line style="fill: none;" marker-end="url(#arrowhead)" stroke="none" stroke-width="2" class="messageLine0" y2="650" x2="949" y1="650" x1="580"></line><g><rect class="note" ry="0" rx="0" height="52" width="233" stroke="#666" fill="#EDF2AE" y="660" x="832.5"></rect><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="665" x="949"><tspan x="949">The bidder can now use the proof</tspan></text><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="681" x="949"><tspan x="949"> to participate in the auction</tspan></text></g><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 16px; font-weight: 400;" dy="1em" class="messageText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="727" x="512">bid (EID, proof(EID, [m,M]))</text><line style="stroke-dasharray: 3, 3; fill: none;" marker-end="url(#arrowhead)" stroke="none" stroke-width="2" class="messageLine1" y2="760" x2="75" y1="760" x1="949"></line><g><rect class="note" ry="0" rx="0" height="52" width="299" stroke="#666" fill="#EDF2AE" y="770" x="799.5"></rect><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="775" x="949"><tspan x="949">The winning bidder provides a release token </tspan></text><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="791" x="949"><tspan x="949"> for the winning amount to the seller</tspan></text></g><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 16px; font-weight: 400;" dy="1em" class="messageText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="837" x="512">EID, DEPOSIT_ID, amount, coins[], sig_b(...)</text><line style="fill: none;" marker-end="url(#arrowhead)" stroke="none" stroke-width="2" class="messageLine0" y2="870" x2="75" y1="870" x1="949"></line><g><rect class="note" ry="0" rx="0" height="36" width="208" stroke="#666" fill="#EDF2AE" y="880" x="-29"></rect><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 14px; font-weight: 400;" dy="1em" class="noteText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="885" x="75"><tspan x="75">The seller can claim the coins</tspan></text></g><text style="font-family: &quot;trebuchet ms&quot;, verdana, arial, sans-serif; font-size: 16px; font-weight: 400;" dy="1em" class="messageText" alignment-baseline="middle" dominant-baseline="middle" text-anchor="middle" y="931" x="325">claim(EID, DEPOSIT_ID, amount, coins[], sig_b, sig_s(sig_b))</text><line style="fill: none;" marker-end="url(#arrowhead)" stroke="none" stroke-width="2" class="messageLine0" y2="964" x2="575" y1="964" x1="75"></line><g><rect class="actor" ry="3" rx="3" height="65" width="150" stroke="#666" fill="#eaeaea" y="984" x="0"></rect><text style="text-anchor: middle; font-size: 14px; font-weight: 400; font-family: &quot;Open Sans&quot;, sans-serif;" class="actor" alignment-baseline="central" dominant-baseline="central" y="1016.5" x="75"><tspan dy="0" x="75">Seller</tspan></text></g><g><rect class="actor" ry="3" rx="3" height="65" width="150" stroke="#666" fill="#eaeaea" y="984" x="500"></rect><text style="text-anchor: middle; font-size: 14px; font-weight: 400; font-family: &quot;Open Sans&quot;, sans-serif;" class="actor" alignment-baseline="central" dominant-baseline="central" y="1016.5" x="575"><tspan dy="0" x="575">Exchange</tspan></text></g><g><rect class="actor" ry="3" rx="3" height="65" width="150" stroke="#666" fill="#eaeaea" y="984" x="874"></rect><text style="text-anchor: middle; font-size: 14px; font-weight: 400; font-family: &quot;Open Sans&quot;, sans-serif;" class="actor" alignment-baseline="central" dominant-baseline="central" y="1016.5" x="949"><tspan dy="0" x="949">Buyer</tspan></text></g></svg>
diff --git a/design-documents/index.rst b/design-documents/index.rst
index f5b8a93e..454564d0 100644
--- a/design-documents/index.rst
+++ b/design-documents/index.rst
@@ -6,7 +6,10 @@ The goal of these documents is to discuss facilitate discussion around
new features while keeping track of the evolution of the whole system
and protocol.
+Design documents that start with "XX" are considered deprecated.
+
.. toctree::
+ :maxdepth: 1
:glob:
001-new-browser-integration
@@ -14,6 +17,7 @@ and protocol.
003-tos-rendering
004-wallet-withdrawal-flow
005-wallet-backup-sync
+ 006-extensions
007-payment
008-fees
009-backup
@@ -27,7 +31,40 @@ and protocol.
017-backoffice-inventory-management
018-contract-json
019-wallet-backup-merge
- 020-backoffice-tips-management
+ 020-backoffice-rewards-management
021-exchange-key-continuity
022-wallet-auditor-reports
+ 023-taler-kyc
+ 024-age-restriction
+ 025-withdraw-from-wallet
+ 026-refund-fees
+ 027-sandboxing-taler.rst
+ 028-deposit-policies
+ 029-mobile-ui
+ 030-offline-payments
+ 031-invoicing
+ 032-brandt-vickrey-auctions
+ 033-database
+ 034-wallet-db-migration
+ 035-regional-currencies
+ 036-currency-conversion-service
+ 037-wallet-transactions-lifecycle.rst
+ 038-demobanks-protocol-suppliers.rst
+ 039-taler-browser-integration.rst
+ 040-distro-packaging.rst
+ 041-wallet-balance-amount-definitions.rst
+ 042-synthetic-wallet-errors.rst
+ 043-managing-prebuilt-artifacts.rst
+ 044-ci-system.rst
+ 045-kyc-inheritance.rst
+ 046-mumimo-contracts.rst
+ 047-stefan.rst
+ 048-wallet-exchange-lifecycle.rst
+ 049-auth.rst
+ 050-libeufin-nexus.rst
+ 051-fractional-digits.rst
+ 052-libeufin-bank-2fa.rst
+ 053-wallet-ui.rst
+ 054-dynamic-form.rst
+ 055-wallet-problem-report.rst
999-template
diff --git a/design-documents/wallet-screenshots/ios-wallet/10-empty-wallet-01.png b/design-documents/wallet-screenshots/ios-wallet/10-empty-wallet-01.png
new file mode 100644
index 00000000..f6ff6bfc
--- /dev/null
+++ b/design-documents/wallet-screenshots/ios-wallet/10-empty-wallet-01.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/10-empty-wallet-latest.png b/design-documents/wallet-screenshots/ios-wallet/10-empty-wallet-latest.png
new file mode 120000
index 00000000..69fa1dbb
--- /dev/null
+++ b/design-documents/wallet-screenshots/ios-wallet/10-empty-wallet-latest.png
@@ -0,0 +1 @@
+10-empty-wallet-01.png \ No newline at end of file
diff --git a/design-documents/wallet-screenshots/ios-wallet/11-balances-list-01.png b/design-documents/wallet-screenshots/ios-wallet/11-balances-list-01.png
new file mode 100644
index 00000000..1cd5e287
--- /dev/null
+++ b/design-documents/wallet-screenshots/ios-wallet/11-balances-list-01.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/11-balances-list-latest.png b/design-documents/wallet-screenshots/ios-wallet/11-balances-list-latest.png
new file mode 120000
index 00000000..93b135ab
--- /dev/null
+++ b/design-documents/wallet-screenshots/ios-wallet/11-balances-list-latest.png
@@ -0,0 +1 @@
+11-balances-list-01.png \ No newline at end of file
diff --git a/design-documents/wallet-screenshots/webex-wallet/READE b/design-documents/wallet-screenshots/webex-wallet/READE
new file mode 100644
index 00000000..597fa22e
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/READE
@@ -0,0 +1,22 @@
+Wallet Web Extension screenshots
+--------------------------------
+
+Screenshoots are organized by common use case using
+the happy path to ilustrate the user flow:
+
+ * withdrawal: starts from an empty wallet and performs
+ a manual withdrawal with demo exchange.
+ * payment: starts from demo shop and pay for an article.
+ also showing how a refund looks.
+ * transfer: performs a p2p push debit and credit.
+ * invoice: performs a p2p pull credit and debit.
+ * deposit: starts from a wallet with some balance
+ and deposit into a bank account new yet
+ known by the wallet.
+ * add-exchange: add the test exchange into the wallet.
+
+In this root folder there are some additionals screen for
+settings, dev tools and others.
+
+Screenshot starting with "store-*" are used in chrome webstore
+and firefox addon store.
diff --git a/design-documents/wallet-screenshots/webex-wallet/add-exchange/1-balance.png b/design-documents/wallet-screenshots/webex-wallet/add-exchange/1-balance.png
new file mode 100644
index 00000000..1041e2ee
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/add-exchange/1-balance.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/add-exchange/10-testkudos-in-the-list.png b/design-documents/wallet-screenshots/webex-wallet/add-exchange/10-testkudos-in-the-list.png
new file mode 100644
index 00000000..12a53026
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/add-exchange/10-testkudos-in-the-list.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/add-exchange/11-select-test-kudos.png b/design-documents/wallet-screenshots/webex-wallet/add-exchange/11-select-test-kudos.png
new file mode 100644
index 00000000..43e18c89
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/add-exchange/11-select-test-kudos.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/add-exchange/2-click-get-cash.png b/design-documents/wallet-screenshots/webex-wallet/add-exchange/2-click-get-cash.png
new file mode 100644
index 00000000..d7d247f0
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/add-exchange/2-click-get-cash.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/add-exchange/3-click-add-exchange.png b/design-documents/wallet-screenshots/webex-wallet/add-exchange/3-click-add-exchange.png
new file mode 100644
index 00000000..7a1a48e9
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/add-exchange/3-click-add-exchange.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/add-exchange/4-input-URL.png b/design-documents/wallet-screenshots/webex-wallet/add-exchange/4-input-URL.png
new file mode 100644
index 00000000..efdf852a
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/add-exchange/4-input-URL.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/add-exchange/5-click-next.png b/design-documents/wallet-screenshots/webex-wallet/add-exchange/5-click-next.png
new file mode 100644
index 00000000..9a2782f2
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/add-exchange/5-click-next.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/add-exchange/6-review-tos.png b/design-documents/wallet-screenshots/webex-wallet/add-exchange/6-review-tos.png
new file mode 100644
index 00000000..44a85d6f
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/add-exchange/6-review-tos.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/add-exchange/7-accept-tos.png b/design-documents/wallet-screenshots/webex-wallet/add-exchange/7-accept-tos.png
new file mode 100644
index 00000000..c73c5256
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/add-exchange/7-accept-tos.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/add-exchange/8-confirm.png b/design-documents/wallet-screenshots/webex-wallet/add-exchange/8-confirm.png
new file mode 100644
index 00000000..1041e2ee
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/add-exchange/8-confirm.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/add-exchange/9-click-get-cash.png b/design-documents/wallet-screenshots/webex-wallet/add-exchange/9-click-get-cash.png
new file mode 100644
index 00000000..d7d247f0
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/add-exchange/9-click-get-cash.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/deposit/1-balance.png b/design-documents/wallet-screenshots/webex-wallet/deposit/1-balance.png
new file mode 100644
index 00000000..7c571c48
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/deposit/1-balance.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/deposit/10-balance.png b/design-documents/wallet-screenshots/webex-wallet/deposit/10-balance.png
new file mode 100644
index 00000000..4e3a787b
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/deposit/10-balance.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/deposit/2-click-send.png b/design-documents/wallet-screenshots/webex-wallet/deposit/2-click-send.png
new file mode 100644
index 00000000..2cdb5fe0
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/deposit/2-click-send.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/deposit/3-click-deposit.png b/design-documents/wallet-screenshots/webex-wallet/deposit/3-click-deposit.png
new file mode 100644
index 00000000..afc4a431
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/deposit/3-click-deposit.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/deposit/4-click-add-account.png b/design-documents/wallet-screenshots/webex-wallet/deposit/4-click-add-account.png
new file mode 100644
index 00000000..c91bc8d9
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/deposit/4-click-add-account.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/deposit/5-complete-form.png b/design-documents/wallet-screenshots/webex-wallet/deposit/5-complete-form.png
new file mode 100644
index 00000000..77514161
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/deposit/5-complete-form.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/deposit/6-click-add.png b/design-documents/wallet-screenshots/webex-wallet/deposit/6-click-add.png
new file mode 100644
index 00000000..e78538c7
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/deposit/6-click-add.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/deposit/7-confirm-deposit.png b/design-documents/wallet-screenshots/webex-wallet/deposit/7-confirm-deposit.png
new file mode 100644
index 00000000..bf2c61bc
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/deposit/7-confirm-deposit.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/deposit/8-show-transaction.png b/design-documents/wallet-screenshots/webex-wallet/deposit/8-show-transaction.png
new file mode 100644
index 00000000..381ae09e
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/deposit/8-show-transaction.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/deposit/9-after-deposit-confirmed.png b/design-documents/wallet-screenshots/webex-wallet/deposit/9-after-deposit-confirmed.png
new file mode 100644
index 00000000..74c2026d
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/deposit/9-after-deposit-confirmed.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/dev-tools.png b/design-documents/wallet-screenshots/webex-wallet/dev-tools.png
new file mode 100644
index 00000000..a817d055
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/dev-tools.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/invoice/1-balance.png b/design-documents/wallet-screenshots/webex-wallet/invoice/1-balance.png
new file mode 100644
index 00000000..a6692c4f
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/invoice/1-balance.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/invoice/10-confirm-transfer.png b/design-documents/wallet-screenshots/webex-wallet/invoice/10-confirm-transfer.png
new file mode 100644
index 00000000..2611c9f3
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/invoice/10-confirm-transfer.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/invoice/11-show-history.png b/design-documents/wallet-screenshots/webex-wallet/invoice/11-show-history.png
new file mode 100644
index 00000000..52907939
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/invoice/11-show-history.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/invoice/2-click-add.png b/design-documents/wallet-screenshots/webex-wallet/invoice/2-click-add.png
new file mode 100644
index 00000000..7834436d
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/invoice/2-click-add.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/invoice/3-input-six.png b/design-documents/wallet-screenshots/webex-wallet/invoice/3-input-six.png
new file mode 100644
index 00000000..0f910210
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/invoice/3-input-six.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/invoice/4-click-invoice.png b/design-documents/wallet-screenshots/webex-wallet/invoice/4-click-invoice.png
new file mode 100644
index 00000000..0d7c1b31
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/invoice/4-click-invoice.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/invoice/5-complete-form.png b/design-documents/wallet-screenshots/webex-wallet/invoice/5-complete-form.png
new file mode 100644
index 00000000..625afb3c
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/invoice/5-complete-form.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/invoice/6-create-invoice.png b/design-documents/wallet-screenshots/webex-wallet/invoice/6-create-invoice.png
new file mode 100644
index 00000000..def698a8
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/invoice/6-create-invoice.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/invoice/7-copy-qr-open-qr-page.png b/design-documents/wallet-screenshots/webex-wallet/invoice/7-copy-qr-open-qr-page.png
new file mode 100644
index 00000000..fe221eac
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/invoice/7-copy-qr-open-qr-page.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/invoice/8-paste-URI.png b/design-documents/wallet-screenshots/webex-wallet/invoice/8-paste-URI.png
new file mode 100644
index 00000000..26351cb9
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/invoice/8-paste-URI.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/invoice/9-click-open.png b/design-documents/wallet-screenshots/webex-wallet/invoice/9-click-open.png
new file mode 100644
index 00000000..90393d3b
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/invoice/9-click-open.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/payment/1-load-shop.png b/design-documents/wallet-screenshots/webex-wallet/payment/1-load-shop.png
new file mode 100644
index 00000000..4aacc47b
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/payment/1-load-shop.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/payment/10-click-article-URL.png b/design-documents/wallet-screenshots/webex-wallet/payment/10-click-article-URL.png
new file mode 100644
index 00000000..74488cb6
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/payment/10-click-article-URL.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/payment/2-click-first-article.png b/design-documents/wallet-screenshots/webex-wallet/payment/2-click-first-article.png
new file mode 100644
index 00000000..31635b8a
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/payment/2-click-first-article.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/payment/3-confirm-payment.png b/design-documents/wallet-screenshots/webex-wallet/payment/3-confirm-payment.png
new file mode 100644
index 00000000..016f5514
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/payment/3-confirm-payment.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/payment/4-click-refund.png b/design-documents/wallet-screenshots/webex-wallet/payment/4-click-refund.png
new file mode 100644
index 00000000..4a3ddd39
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/payment/4-click-refund.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/payment/5-click-request-refund.png b/design-documents/wallet-screenshots/webex-wallet/payment/5-click-request-refund.png
new file mode 100644
index 00000000..9b27cd5b
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/payment/5-click-request-refund.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/payment/6-accept-refund.png b/design-documents/wallet-screenshots/webex-wallet/payment/6-accept-refund.png
new file mode 100644
index 00000000..a4b1c137
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/payment/6-accept-refund.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/payment/7-click-refund-detail.png b/design-documents/wallet-screenshots/webex-wallet/payment/7-click-refund-detail.png
new file mode 100644
index 00000000..14291836
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/payment/7-click-refund-detail.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/payment/8-show-history.png b/design-documents/wallet-screenshots/webex-wallet/payment/8-show-history.png
new file mode 100644
index 00000000..2758f7f3
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/payment/8-show-history.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/payment/9-click-receipt.png b/design-documents/wallet-screenshots/webex-wallet/payment/9-click-receipt.png
new file mode 100644
index 00000000..a4b1c137
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/payment/9-click-receipt.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/scan-qr-code.png b/design-documents/wallet-screenshots/webex-wallet/scan-qr-code.png
new file mode 100644
index 00000000..ae28e3db
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/scan-qr-code.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/settings-developer-mode.png b/design-documents/wallet-screenshots/webex-wallet/settings-developer-mode.png
new file mode 100644
index 00000000..c93883dc
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/settings-developer-mode.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/settings-normal-mode.png b/design-documents/wallet-screenshots/webex-wallet/settings-normal-mode.png
new file mode 100644
index 00000000..50f70cab
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/settings-normal-mode.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/store-installed.png b/design-documents/wallet-screenshots/webex-wallet/store-installed.png
new file mode 100644
index 00000000..67c481fc
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/store-installed.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/store-payment.png b/design-documents/wallet-screenshots/webex-wallet/store-payment.png
new file mode 100644
index 00000000..3f776696
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/store-payment.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/store-withdraw.png b/design-documents/wallet-screenshots/webex-wallet/store-withdraw.png
new file mode 100644
index 00000000..8409a0b9
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/store-withdraw.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/transfer/1-initial-balance.png b/design-documents/wallet-screenshots/webex-wallet/transfer/1-initial-balance.png
new file mode 100644
index 00000000..20e74cf3
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/transfer/1-initial-balance.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/transfer/10-open-URI.png b/design-documents/wallet-screenshots/webex-wallet/transfer/10-open-URI.png
new file mode 100644
index 00000000..22f21f89
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/transfer/10-open-URI.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/transfer/11-accept-transfer.png b/design-documents/wallet-screenshots/webex-wallet/transfer/11-accept-transfer.png
new file mode 100644
index 00000000..9ee2083a
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/transfer/11-accept-transfer.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/transfer/12-show-history.png b/design-documents/wallet-screenshots/webex-wallet/transfer/12-show-history.png
new file mode 100644
index 00000000..d2d12ca8
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/transfer/12-show-history.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/transfer/2-click-send.png b/design-documents/wallet-screenshots/webex-wallet/transfer/2-click-send.png
new file mode 100644
index 00000000..0e705860
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/transfer/2-click-send.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/transfer/3-amount-five.png b/design-documents/wallet-screenshots/webex-wallet/transfer/3-amount-five.png
new file mode 100644
index 00000000..ffe4bee7
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/transfer/3-amount-five.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/transfer/4-send-wallet.png b/design-documents/wallet-screenshots/webex-wallet/transfer/4-send-wallet.png
new file mode 100644
index 00000000..f566b0cb
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/transfer/4-send-wallet.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/transfer/5-complete-form.png b/design-documents/wallet-screenshots/webex-wallet/transfer/5-complete-form.png
new file mode 100644
index 00000000..836755ca
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/transfer/5-complete-form.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/transfer/6-confirm-transfer.png b/design-documents/wallet-screenshots/webex-wallet/transfer/6-confirm-transfer.png
new file mode 100644
index 00000000..55de4bb0
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/transfer/6-confirm-transfer.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/transfer/7-show-history.png b/design-documents/wallet-screenshots/webex-wallet/transfer/7-show-history.png
new file mode 100644
index 00000000..39de7b66
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/transfer/7-show-history.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/transfer/8-scan-qr.png b/design-documents/wallet-screenshots/webex-wallet/transfer/8-scan-qr.png
new file mode 100644
index 00000000..cacdce06
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/transfer/8-scan-qr.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/transfer/9-paste-URI.png b/design-documents/wallet-screenshots/webex-wallet/transfer/9-paste-URI.png
new file mode 100644
index 00000000..32ac0ff4
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/transfer/9-paste-URI.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/withdrawal/10-transaction-completed.png b/design-documents/wallet-screenshots/webex-wallet/withdrawal/10-transaction-completed.png
new file mode 100644
index 00000000..2a774334
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/withdrawal/10-transaction-completed.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/withdrawal/11-history-after-withdraw.png b/design-documents/wallet-screenshots/webex-wallet/withdrawal/11-history-after-withdraw.png
new file mode 100644
index 00000000..54b05212
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/withdrawal/11-history-after-withdraw.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/withdrawal/2-empty-wallet.png b/design-documents/wallet-screenshots/webex-wallet/withdrawal/2-empty-wallet.png
new file mode 100644
index 00000000..79fc787b
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/withdrawal/2-empty-wallet.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/withdrawal/3-get-digital-cash.png b/design-documents/wallet-screenshots/webex-wallet/withdrawal/3-get-digital-cash.png
new file mode 100644
index 00000000..273d5f5f
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/withdrawal/3-get-digital-cash.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/withdrawal/4-select-kudos.png b/design-documents/wallet-screenshots/webex-wallet/withdrawal/4-select-kudos.png
new file mode 100644
index 00000000..741ac32a
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/withdrawal/4-select-kudos.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/withdrawal/5-set-amount-five.png b/design-documents/wallet-screenshots/webex-wallet/withdrawal/5-set-amount-five.png
new file mode 100644
index 00000000..8454928b
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/withdrawal/5-set-amount-five.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/withdrawal/6-withdraw-from-bank.png b/design-documents/wallet-screenshots/webex-wallet/withdrawal/6-withdraw-from-bank.png
new file mode 100644
index 00000000..e0942a0c
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/withdrawal/6-withdraw-from-bank.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/withdrawal/7-review-tos.png b/design-documents/wallet-screenshots/webex-wallet/withdrawal/7-review-tos.png
new file mode 100644
index 00000000..505e06d3
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/withdrawal/7-review-tos.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/withdrawal/8-accept-tos.png b/design-documents/wallet-screenshots/webex-wallet/withdrawal/8-accept-tos.png
new file mode 100644
index 00000000..61d3c0a4
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/withdrawal/8-accept-tos.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/webex-wallet/withdrawal/9-confirm-withdraw.png b/design-documents/wallet-screenshots/webex-wallet/withdrawal/9-confirm-withdraw.png
new file mode 100644
index 00000000..579803cc
--- /dev/null
+++ b/design-documents/wallet-screenshots/webex-wallet/withdrawal/9-confirm-withdraw.png
Binary files differ
diff --git a/exchange-db.png b/exchange-db.png
deleted file mode 100644
index f99e2664..00000000
--- a/exchange-db.png
+++ /dev/null
Binary files differ
diff --git a/extract-tsdefs/.gitignore b/extract-tsdefs/.gitignore
new file mode 100644
index 00000000..fa298802
--- /dev/null
+++ b/extract-tsdefs/.gitignore
@@ -0,0 +1,3 @@
+extract.js
+node_modules/
+dist
diff --git a/extract-tsdefs/README.md b/extract-tsdefs/README.md
new file mode 100644
index 00000000..e668be8d
--- /dev/null
+++ b/extract-tsdefs/README.md
@@ -0,0 +1,8 @@
+# Auto-generated wallet-core API docs
+
+Usage:
+```
+pnpm install
+pnpm run compile
+node dist/extract.js $WALLET_CORE_DIR $OUTFILENAME
+```
diff --git a/extract-tsdefs/extract.ts b/extract-tsdefs/extract.ts
new file mode 100644
index 00000000..5be82479
--- /dev/null
+++ b/extract-tsdefs/extract.ts
@@ -0,0 +1,341 @@
+/*
+ This file is part of GNU Taler
+ (C) 2022 Taler Systems S.A.
+
+ GNU Taler 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.
+
+ GNU 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+import * as ts from "typescript";
+import * as fs from "fs/promises";
+import * as path from "path";
+import * as prettier from "prettier";
+
+if (process.argv.length != 4) {
+ console.log(
+ `usage: ${process.argv[0]} ${process.argv[1]} WALLET_CORE_REPO OUTFILE`
+ );
+ process.exit(2);
+}
+
+const walletRootDir = process.argv[2];
+const outfile = process.argv[3];
+
+const walletCoreDir = path.join(walletRootDir, "packages/taler-wallet-core");
+const excludedNames = new Set([
+ "TalerErrorCode",
+ "WalletBackupContentV1",
+ "Array",
+]);
+
+const configFile = ts.findConfigFile(
+ walletCoreDir,
+ ts.sys.fileExists,
+ "tsconfig.json"
+);
+if (!configFile) throw Error("tsconfig.json not found");
+const { config } = ts.readConfigFile(configFile, ts.sys.readFile);
+
+const { options, fileNames, errors } = ts.parseJsonConfigFileContent(
+ config,
+ ts.sys,
+ walletCoreDir
+);
+
+const program = ts.createProgram({
+ options,
+ rootNames: fileNames,
+ configFileParsingDiagnostics: errors,
+});
+
+const checker = program.getTypeChecker();
+
+const walletApiTypesFiles = `${walletCoreDir}/src/wallet-api-types.ts`;
+console.log("api types file:", walletApiTypesFiles);
+
+const sourceFile = program.getSourceFile(walletApiTypesFiles);
+
+if (!sourceFile) {
+ throw Error();
+}
+
+const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
+
+const fileSymbol = program.getTypeChecker().getSymbolAtLocation(sourceFile);
+
+const expo = fileSymbol?.exports;
+if (!expo) {
+ throw Error();
+}
+
+interface PerOpGatherState {
+ opName: string;
+ nameSet: Set<string>;
+ group: string;
+ /**
+ * Enum member declaration in the form 'Foo = "bar"'.
+ */
+ enumMemberDecl: string | undefined;
+}
+
+interface GatherState {
+ declTexts: Map<string, string>;
+}
+
+function gatherDecls(
+ node: ts.Node,
+ gatherState: GatherState,
+ perOpState: PerOpGatherState
+): void {
+ switch (node.kind) {
+ case ts.SyntaxKind.EnumDeclaration:
+ // Always handled via parent
+ return;
+ case ts.SyntaxKind.Identifier:
+ case ts.SyntaxKind.TypeReference: {
+ console.log(`start typeref-or-id ${node.getText()}`);
+ const type = checker.getTypeAtLocation(node);
+ if (type.flags === ts.TypeFlags.String) {
+ console.log("string!");
+ break;
+ }
+ const symbol = type.symbol || type.aliasSymbol;
+ if (!symbol) {
+ console.log(`no type symbol for ${node.getText()}`);
+ break;
+ }
+ const name = symbol.name;
+ console.log(`symbol name: ${type.symbol?.name}`);
+ console.log(`alias symbol name: ${type.aliasSymbol?.name}`);
+ if (perOpState.nameSet.has(name)) {
+ console.log("already found!");
+ break;
+ }
+ perOpState.nameSet.add(name);
+ if (excludedNames.has(name)) {
+ console.log("excluded!");
+ break;
+ }
+ const decls = symbol.getDeclarations();
+ decls?.forEach((decl) => {
+ const sourceFilename = decl.getSourceFile().fileName;
+ if (path.basename(sourceFilename).startsWith("lib.")) {
+ return;
+ }
+ switch (decl.kind) {
+ case ts.SyntaxKind.EnumMember: {
+ gatherDecls(decl.parent, gatherState, perOpState);
+ console.log("enum member", decl.getText());
+ break;
+ }
+ case ts.SyntaxKind.InterfaceDeclaration:
+ case ts.SyntaxKind.EnumDeclaration:
+ case ts.SyntaxKind.TypeAliasDeclaration: {
+ const declText = printer.printNode(
+ ts.EmitHint.Unspecified,
+ decl,
+ decl.getSourceFile()!
+ );
+ gatherState.declTexts.set(name, declText);
+ console.log(declText);
+ break;
+ }
+ default:
+ console.log(`unknown decl kind ${ts.SyntaxKind[decl.kind]}`);
+ break;
+ }
+ gatherDecls(decl, gatherState, perOpState);
+ console.log(`end typeref-or-id ${node.getText()}`);
+ });
+ break;
+ }
+ default:
+ break;
+ }
+ console.log(`syntax children for ${node.getText()}`);
+ node.forEachChild((child) => {
+ console.log(`syntax child: ${ts.SyntaxKind[child.kind]}`);
+ gatherDecls(child, gatherState, perOpState);
+ });
+ //console.log(`// unknown node kind ${ts.SyntaxKind[node.kind]}`);
+ return;
+}
+
+function getOpEnumDecl(decl: ts.Declaration): string | undefined {
+ let enumMemberDecl: undefined | string = undefined;
+ function walk(node: ts.Node) {
+ node.forEachChild((x) => {
+ console.log(`child kind: ${ts.SyntaxKind[x.kind]}`);
+ console.log(x.getText());
+ switch (x.kind) {
+ case ts.SyntaxKind.PropertySignature: {
+ const sig = x as ts.PropertySignature;
+ if (sig.name.getText() == "op") {
+ const type = checker.getTypeFromTypeNode(sig.type!);
+ enumMemberDecl = type.symbol.declarations![0]!.getText();
+ }
+ break;
+ }
+ }
+ walk(x);
+ });
+ }
+ walk(decl);
+ return enumMemberDecl;
+}
+
+const main = async () => {
+ const f = await fs.open(outfile, "w");
+ const gatherState: GatherState = {
+ declTexts: new Map<string, string>(),
+ };
+ const perOpStates: PerOpGatherState[] = [];
+
+ let currentGroup: string = "Unknown Group";
+
+ expo.forEach((v, k) => {
+ if (!v.name.endsWith("Op")) {
+ return;
+ }
+ const decls = v.getDeclarations();
+ decls?.forEach((decl) => {
+ console.log(`export decl, kind ${ts.SyntaxKind[decl.kind]}`);
+
+ const commentRanges = ts.getLeadingCommentRanges(
+ sourceFile.getFullText(),
+ decl.getFullStart()
+ );
+ commentRanges?.forEach((r) => {
+ const text = sourceFile.getFullText().slice(r.pos, r.end);
+ console.log("comment text:", text);
+ const groupPrefix = "group:";
+ const loc = text.indexOf(groupPrefix);
+ if (loc >= 0) {
+ const groupName = text.slice(loc + groupPrefix.length);
+ console.log("got new group", groupName);
+ currentGroup = groupName;
+ }
+ });
+
+ const perOpState: PerOpGatherState = {
+ opName: v.name,
+ nameSet: new Set<string>(),
+ group: currentGroup,
+ enumMemberDecl: getOpEnumDecl(decl),
+ };
+ let declText = printer.printNode(
+ ts.EmitHint.Unspecified,
+ decl,
+ decl.getSourceFile()!
+ );
+ if (perOpState.enumMemberDecl) {
+ declText = declText + `\n// ${perOpState.enumMemberDecl}\n`;
+ }
+ console.log("replacing group in", declText);
+ // Remove group comments
+ declText = declText.replace(/\/\/ group: [^\n]*[\n]/m, "");
+ perOpState.nameSet.add(v.name);
+ gatherState.declTexts.set(v.name, declText);
+ gatherDecls(decl, gatherState, perOpState);
+ perOpStates.push(perOpState);
+ });
+ });
+
+ const allNames: Set<string> = new Set();
+
+ for (const g of perOpStates) {
+ for (const k of g.nameSet.values()) {
+ allNames.add(k);
+ }
+ }
+
+ const commonNames: Set<string> = new Set();
+
+ for (const name of allNames) {
+ let count = 0;
+ for (const g of perOpStates) {
+ for (const k of g.nameSet.values()) {
+ if (name === k) {
+ count++;
+ }
+ }
+ }
+ if (count > 1) {
+ console.log(`common name: ${name}`);
+ commonNames.add(name);
+ }
+ }
+
+ const groups = new Set<string>();
+ for (const g of perOpStates) {
+ groups.add(g.group);
+ }
+
+ await f.write(`# Wallet-Core API Documentation\n`);
+
+ await f.write(
+ `This file is auto-generated from [wallet-core](https://git.taler.net/wallet-core.git/tree/packages/taler-wallet-core/src/wallet-api-types.ts).\n`
+ );
+
+ await f.write(`## Overview\n`);
+ for (const g of groups.values()) {
+ await f.write(`### ${g}\n`);
+ for (const op of perOpStates) {
+ if (op.group !== g) {
+ continue;
+ }
+ await f.write(`* [${op.opName}](#${op.opName.toLowerCase()})\n`);
+ }
+ }
+
+ await f.write(`## Operation Reference\n`);
+ for (const g of perOpStates) {
+ // Not yet supported, switch to myst first!
+ // await f.write(`(${g.opName.toLowerCase()})=\n`);
+ await f.write(`### ${g.opName}\n`);
+ for (const name of g.nameSet.values()) {
+ if (commonNames.has(name)) {
+ continue;
+ }
+ const text = gatherState.declTexts.get(name);
+ if (!text) {
+ continue;
+ }
+ await f.write("```typescript\n");
+ const formatted = prettier.format(text, {
+ semi: true,
+ parser: "typescript",
+ });
+ await f.write(`${formatted}\n`);
+ await f.write("```\n");
+ }
+ await f.write("\n");
+ }
+
+ await f.write(`## Common Declarations\n`);
+ for (const name of commonNames.values()) {
+ const text = gatherState.declTexts.get(name);
+ if (!text) {
+ continue;
+ }
+ await f.write("```typescript\n");
+ const formatted = prettier.format(text, {
+ semi: true,
+ parser: "typescript",
+ });
+ await f.write(`${formatted}`);
+ await f.write("```\n");
+ }
+
+ await f.close();
+};
+
+main();
diff --git a/extract-tsdefs/foo b/extract-tsdefs/foo
new file mode 100644
index 00000000..ade427c7
--- /dev/null
+++ b/extract-tsdefs/foo
@@ -0,0 +1,3562 @@
+# Wallet-Core API Documentation
+This file is auto-generated from [wallet-core](https://git.taler.net/wallet-core.git/tree/packages/taler-wallet-core/src/wallet-api-types.ts).
+## Overview
+### Unknown Group
+* [InitWalletOp](#initwalletop)
+* [GetVersionOp](#getversionop)
+### Basic Wallet Information
+* [GetBalancesOp](#getbalancesop)
+* [GetBalancesDetailOp](#getbalancesdetailop)
+### Managing Transactions
+* [GetTransactionsOp](#gettransactionsop)
+* [GetTransactionByIdOp](#gettransactionbyidop)
+* [RetryPendingNowOp](#retrypendingnowop)
+* [DeleteTransactionOp](#deletetransactionop)
+* [RetryTransactionOp](#retrytransactionop)
+* [AbortTransactionOp](#aborttransactionop)
+* [SuspendTransactionOp](#suspendtransactionop)
+* [ResumeTransactionOp](#resumetransactionop)
+### Withdrawals
+* [GetWithdrawalDetailsForAmountOp](#getwithdrawaldetailsforamountop)
+* [GetWithdrawalDetailsForUriOp](#getwithdrawaldetailsforuriop)
+* [AcceptBankIntegratedWithdrawalOp](#acceptbankintegratedwithdrawalop)
+* [AcceptManualWithdrawalOp](#acceptmanualwithdrawalop)
+### Merchant Payments
+* [PreparePayForUriOp](#preparepayforuriop)
+* [PreparePayForTemplateOp](#preparepayfortemplateop)
+* [GetContractTermsDetailsOp](#getcontracttermsdetailsop)
+* [ConfirmPayOp](#confirmpayop)
+* [ApplyRefundOp](#applyrefundop)
+* [ApplyRefundFromPurchaseIdOp](#applyrefundfrompurchaseidop)
+* [PrepareRefundOp](#preparerefundop)
+### Tipping
+* [PrepareTipOp](#preparetipop)
+* [AcceptTipOp](#accepttipop)
+### Exchange Management
+* [ListExchangesOp](#listexchangesop)
+* [AddExchangeOp](#addexchangeop)
+* [ListKnownBankAccountsOp](#listknownbankaccountsop)
+* [AddKnownBankAccountsOp](#addknownbankaccountsop)
+* [ForgetKnownBankAccountsOp](#forgetknownbankaccountsop)
+* [SetExchangeTosAcceptedOp](#setexchangetosacceptedop)
+* [GetExchangeTosOp](#getexchangetosop)
+* [GetExchangeDetailedInfoOp](#getexchangedetailedinfoop)
+* [ListCurrenciesOp](#listcurrenciesop)
+### Deposits
+* [GenerateDepositGroupTxIdOp](#generatedepositgrouptxidop)
+* [CreateDepositGroupOp](#createdepositgroupop)
+* [PrepareDepositOp](#preparedepositop)
+### Backups
+* [ExportBackupRecoveryOp](#exportbackuprecoveryop)
+* [ImportBackupRecoveryOp](#importbackuprecoveryop)
+* [RunBackupCycleOp](#runbackupcycleop)
+* [ExportBackupOp](#exportbackupop)
+* [AddBackupProviderOp](#addbackupproviderop)
+* [RemoveBackupProviderOp](#removebackupproviderop)
+* [GetBackupInfoOp](#getbackupinfoop)
+* [SetWalletDeviceIdOp](#setwalletdeviceidop)
+* [ExportBackupPlainOp](#exportbackupplainop)
+### Peer Payments
+* [CheckPeerPushDebitOp](#checkpeerpushdebitop)
+* [InitiatePeerPushDebitOp](#initiatepeerpushdebitop)
+* [PreparePeerPushCreditOp](#preparepeerpushcreditop)
+* [ConfirmPeerPushCreditOp](#confirmpeerpushcreditop)
+* [CheckPeerPullCreditOp](#checkpeerpullcreditop)
+* [InitiatePeerPullCreditOp](#initiatepeerpullcreditop)
+* [PreparePeerPullDebitOp](#preparepeerpulldebitop)
+* [ConfirmPeerPullDebitOp](#confirmpeerpulldebitop)
+### Data Validation
+* [ValidateIbanOp](#validateibanop)
+### Database Management
+* [ExportDbOp](#exportdbop)
+* [ImportDbOp](#importdbop)
+* [ClearDbOp](#cleardbop)
+* [RecycleOp](#recycleop)
+### Testing and Debugging
+* [ApplyDevExperimentOp](#applydevexperimentop)
+* [RunIntegrationTestOp](#runintegrationtestop)
+* [RunIntegrationTestV2Op](#runintegrationtestv2op)
+* [TestCryptoOp](#testcryptoop)
+* [WithdrawTestBalanceOp](#withdrawtestbalanceop)
+* [WithdrawTestkudosOp](#withdrawtestkudosop)
+* [TestPayOp](#testpayop)
+* [WithdrawFakebankOp](#withdrawfakebankop)
+* [GetPendingTasksOp](#getpendingtasksop)
+* [DumpCoinsOp](#dumpcoinsop)
+* [SetCoinSuspendedOp](#setcoinsuspendedop)
+* [ForceRefreshOp](#forcerefreshop)
+## Operation Reference
+### InitWalletOp
+```typescript
+/**
+ * Initialize wallet-core.
+ *
+ * Must be the request before any other operations.
+ */
+export type InitWalletOp = {
+ op: WalletApiOperation.InitWallet;
+ request: InitRequest;
+ response: InitResponse;
+};
+// InitWallet = "initWallet"
+
+```
+```typescript
+export interface InitRequest {
+ skipDefaults?: boolean;
+}
+
+```
+```typescript
+export interface InitResponse {
+ versionInfo: WalletCoreVersion;
+}
+
+```
+
+### GetVersionOp
+```typescript
+export type GetVersionOp = {
+ op: WalletApiOperation.GetVersion;
+ request: EmptyObject;
+ response: WalletCoreVersion;
+};
+// GetVersion = "getVersion"
+
+```
+
+### GetBalancesOp
+```typescript
+/**
+ * Get current wallet balance.
+ */
+export type GetBalancesOp = {
+ op: WalletApiOperation.GetBalances;
+ request: EmptyObject;
+ response: BalancesResponse;
+};
+// GetBalances = "getBalances"
+
+```
+```typescript
+export interface BalancesResponse {
+ balances: Balance[];
+}
+
+```
+```typescript
+export interface Balance {
+ scopeInfo: ScopeInfo;
+ available: AmountString;
+ pendingIncoming: AmountString;
+ pendingOutgoing: AmountString;
+ hasPendingTransactions: boolean;
+ requiresUserInput: boolean;
+}
+
+```
+```typescript
+export type ScopeInfo =
+ | {
+ type: ScopeType.Global;
+ currency: string;
+ }
+ | {
+ type: ScopeType.Exchange;
+ currency: string;
+ url: string;
+ }
+ | {
+ type: ScopeType.Auditor;
+ currency: string;
+ url: string;
+ };
+
+```
+
+### GetBalancesDetailOp
+```typescript
+export type GetBalancesDetailOp = {
+ op: WalletApiOperation.GetBalanceDetail;
+ request: GetBalanceDetailRequest;
+ response: MerchantPaymentBalanceDetails;
+};
+// GetBalanceDetail = "getBalanceDetail"
+
+```
+```typescript
+export interface GetBalanceDetailRequest {
+ currency: string;
+}
+
+```
+```typescript
+export interface MerchantPaymentBalanceDetails {
+ /**
+ * Balance of type "available" (see balance.ts for definition).
+ */
+ balanceAvailable: AmountJson;
+ /**
+ * Balance of type "material" (see balance.ts for definition).
+ */
+ balanceMaterial: AmountJson;
+ /**
+ * Balance of type "age-acceptable" (see balance.ts for definition).
+ */
+ balanceAgeAcceptable: AmountJson;
+ /**
+ * Balance of type "merchant-acceptable" (see balance.ts for definition).
+ */
+ balanceMerchantAcceptable: AmountJson;
+ /**
+ * Balance of type "merchant-depositable" (see balance.ts for definition).
+ */
+ balanceMerchantDepositable: AmountJson;
+}
+
+```
+```typescript
+/**
+ * Non-negative financial amount. Fractional values are expressed as multiples
+ * of 1e-8.
+ */
+export interface AmountJson {
+ /**
+ * Value, must be an integer.
+ */
+ readonly value: number;
+ /**
+ * Fraction, must be an integer. Represent 1/1e8 of a unit.
+ */
+ readonly fraction: number;
+ /**
+ * Currency of the amount.
+ */
+ readonly currency: string;
+}
+
+```
+
+### GetTransactionsOp
+```typescript
+/**
+ * Get transactions.
+ */
+export type GetTransactionsOp = {
+ op: WalletApiOperation.GetTransactions;
+ request: TransactionsRequest;
+ response: TransactionsResponse;
+};
+// GetTransactions = "getTransactions"
+
+```
+```typescript
+export interface TransactionsRequest {
+ /**
+ * return only transactions in the given currency
+ */
+ currency?: string;
+ /**
+ * if present, results will be limited to transactions related to the given search string
+ */
+ search?: string;
+ /**
+ * If true, include all refreshes in the transactions list.
+ */
+ includeRefreshes?: boolean;
+}
+
+```
+```typescript
+export interface TransactionsResponse {
+ transactions: Transaction[];
+}
+
+```
+
+### GetTransactionByIdOp
+```typescript
+export type GetTransactionByIdOp = {
+ op: WalletApiOperation.GetTransactionById;
+ request: TransactionByIdRequest;
+ response: Transaction;
+};
+// GetTransactionById = "getTransactionById"
+
+```
+```typescript
+export interface TransactionByIdRequest {
+ transactionId: string;
+}
+
+```
+
+### RetryPendingNowOp
+```typescript
+export type RetryPendingNowOp = {
+ op: WalletApiOperation.RetryPendingNow;
+ request: EmptyObject;
+ response: EmptyObject;
+};
+// RetryPendingNow = "retryPendingNow"
+
+```
+
+### DeleteTransactionOp
+```typescript
+/**
+ * Delete a transaction locally in the wallet.
+ */
+export type DeleteTransactionOp = {
+ op: WalletApiOperation.DeleteTransaction;
+ request: DeleteTransactionRequest;
+ response: EmptyObject;
+};
+// DeleteTransaction = "deleteTransaction"
+
+```
+```typescript
+export interface DeleteTransactionRequest {
+ transactionId: string;
+}
+
+```
+
+### RetryTransactionOp
+```typescript
+/**
+ * Immediately retry a transaction.
+ */
+export type RetryTransactionOp = {
+ op: WalletApiOperation.RetryTransaction;
+ request: RetryTransactionRequest;
+ response: EmptyObject;
+};
+// RetryTransaction = "retryTransaction"
+
+```
+```typescript
+export interface RetryTransactionRequest {
+ transactionId: string;
+}
+
+```
+
+### AbortTransactionOp
+```typescript
+/**
+ * Abort a transaction
+ *
+ * For payment transactions, it puts the payment into an "aborting" state.
+ */
+export type AbortTransactionOp = {
+ op: WalletApiOperation.AbortTransaction;
+ request: AbortTransactionRequest;
+ response: EmptyObject;
+};
+// AbortTransaction = "abortTransaction"
+
+```
+
+### SuspendTransactionOp
+```typescript
+/**
+ * Suspend a transaction
+ */
+export type SuspendTransactionOp = {
+ op: WalletApiOperation.SuspendTransaction;
+ request: AbortTransactionRequest;
+ response: EmptyObject;
+};
+// SuspendTransaction = "suspendTransaction"
+
+```
+
+### ResumeTransactionOp
+```typescript
+/**
+ * Resume a transaction
+ */
+export type ResumeTransactionOp = {
+ op: WalletApiOperation.ResumeTransaction;
+ request: AbortTransactionRequest;
+ response: EmptyObject;
+};
+// ResumeTransaction = "resumeTransaction"
+
+```
+
+### GetWithdrawalDetailsForAmountOp
+```typescript
+/**
+ * Get details for withdrawing a particular amount (manual withdrawal).
+ */
+export type GetWithdrawalDetailsForAmountOp = {
+ op: WalletApiOperation.GetWithdrawalDetailsForAmount;
+ request: GetWithdrawalDetailsForAmountRequest;
+ response: ManualWithdrawalDetails;
+};
+// GetWithdrawalDetailsForAmount = "getWithdrawalDetailsForAmount"
+
+```
+```typescript
+export interface GetWithdrawalDetailsForAmountRequest {
+ exchangeBaseUrl: string;
+ amount: string;
+ restrictAge?: number;
+}
+
+```
+```typescript
+export interface ManualWithdrawalDetails {
+ /**
+ * Did the user accept the current version of the exchange's
+ * terms of service?
+ */
+ tosAccepted: boolean;
+ /**
+ * Amount that the user will transfer to the exchange.
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount that will be added to the user's wallet balance.
+ */
+ amountEffective: AmountString;
+ /**
+ * Ways to pay the exchange.
+ */
+ paytoUris: string[];
+ /**
+ * If the exchange supports age-restricted coins it will return
+ * the array of ages.
+ */
+ ageRestrictionOptions?: number[];
+}
+
+```
+
+### GetWithdrawalDetailsForUriOp
+```typescript
+/**
+ * Get details for withdrawing via a particular taler:// URI.
+ */
+export type GetWithdrawalDetailsForUriOp = {
+ op: WalletApiOperation.GetWithdrawalDetailsForUri;
+ request: GetWithdrawalDetailsForUriRequest;
+ response: WithdrawUriInfoResponse;
+};
+// GetWithdrawalDetailsForUri = "getWithdrawalDetailsForUri"
+
+```
+```typescript
+export interface GetWithdrawalDetailsForUriRequest {
+ talerWithdrawUri: string;
+ restrictAge?: number;
+}
+
+```
+```typescript
+export interface WithdrawUriInfoResponse {
+ amount: AmountString;
+ defaultExchangeBaseUrl?: string;
+ possibleExchanges: ExchangeListItem[];
+}
+
+```
+
+### AcceptBankIntegratedWithdrawalOp
+```typescript
+/**
+ * Accept a bank-integrated withdrawal.
+ */
+export type AcceptBankIntegratedWithdrawalOp = {
+ op: WalletApiOperation.AcceptBankIntegratedWithdrawal;
+ request: AcceptBankIntegratedWithdrawalRequest;
+ response: AcceptWithdrawalResponse;
+};
+// AcceptBankIntegratedWithdrawal = "acceptBankIntegratedWithdrawal"
+
+```
+```typescript
+export interface AcceptBankIntegratedWithdrawalRequest {
+ talerWithdrawUri: string;
+ exchangeBaseUrl: string;
+ forcedDenomSel?: ForcedDenomSel;
+ restrictAge?: number;
+}
+
+```
+```typescript
+export interface AcceptWithdrawalResponse {
+ reservePub: string;
+ confirmTransferUrl?: string;
+ transactionId: string;
+}
+
+```
+
+### AcceptManualWithdrawalOp
+```typescript
+/**
+ * Create a manual withdrawal.
+ */
+export type AcceptManualWithdrawalOp = {
+ op: WalletApiOperation.AcceptManualWithdrawal;
+ request: AcceptManualWithdrawalRequest;
+ response: AcceptManualWithdrawalResult;
+};
+// AcceptManualWithdrawal = "acceptManualWithdrawal"
+
+```
+```typescript
+export interface AcceptManualWithdrawalRequest {
+ exchangeBaseUrl: string;
+ amount: string;
+ restrictAge?: number;
+}
+
+```
+```typescript
+export interface AcceptManualWithdrawalResult {
+ /**
+ * Payto URIs that can be used to fund the withdrawal.
+ */
+ exchangePaytoUris: string[];
+ /**
+ * Public key of the newly created reserve.
+ */
+ reservePub: string;
+ transactionId: string;
+}
+
+```
+
+### PreparePayForUriOp
+```typescript
+/**
+ * Prepare to make a payment based on a taler://pay/ URI.
+ */
+export type PreparePayForUriOp = {
+ op: WalletApiOperation.PreparePayForUri;
+ request: PreparePayRequest;
+ response: PreparePayResult;
+};
+// PreparePayForUri = "preparePayForUri"
+
+```
+```typescript
+export interface PreparePayRequest {
+ talerPayUri: string;
+}
+
+```
+
+### PreparePayForTemplateOp
+```typescript
+/**
+ * Prepare to make a payment based on a taler://pay-template/ URI.
+ */
+export type PreparePayForTemplateOp = {
+ op: WalletApiOperation.PreparePayForTemplate;
+ request: PreparePayTemplateRequest;
+ response: PreparePayResult;
+};
+// PreparePayForTemplate = "preparePayForTemplate"
+
+```
+```typescript
+export interface PreparePayTemplateRequest {
+ talerPayTemplateUri: string;
+ templateParams: Record<string, string>;
+}
+
+```
+
+### GetContractTermsDetailsOp
+```typescript
+export type GetContractTermsDetailsOp = {
+ op: WalletApiOperation.GetContractTermsDetails;
+ request: GetContractTermsDetailsRequest;
+ response: WalletContractData;
+};
+// GetContractTermsDetails = "getContractTermsDetails"
+
+```
+```typescript
+export interface GetContractTermsDetailsRequest {
+ proposalId: string;
+}
+
+```
+```typescript
+/**
+ * Data extracted from the contract terms that is relevant for payment
+ * processing in the wallet.
+ */
+export interface WalletContractData {
+ products?: Product[];
+ summaryI18n:
+ | {
+ [lang_tag: string]: string;
+ }
+ | undefined;
+ /**
+ * Fulfillment URL, or the empty string if the order has no fulfillment URL.
+ *
+ * Stored as a non-nullable string as we use this field for IndexedDB indexing.
+ */
+ fulfillmentUrl: string;
+ contractTermsHash: string;
+ fulfillmentMessage?: string;
+ fulfillmentMessageI18n?: InternationalizedString;
+ merchantSig: string;
+ merchantPub: string;
+ merchant: MerchantInfo;
+ amount: AmountString;
+ orderId: string;
+ merchantBaseUrl: string;
+ summary: string;
+ autoRefund: TalerProtocolDuration | undefined;
+ maxWireFee: AmountString;
+ wireFeeAmortization: number;
+ payDeadline: TalerProtocolTimestamp;
+ refundDeadline: TalerProtocolTimestamp;
+ allowedAuditors: AllowedAuditorInfo[];
+ allowedExchanges: AllowedExchangeInfo[];
+ timestamp: TalerProtocolTimestamp;
+ wireMethod: string;
+ wireInfoHash: string;
+ maxDepositFee: AmountString;
+ minimumAge?: number;
+ deliveryDate: TalerProtocolTimestamp | undefined;
+ deliveryLocation: Location | undefined;
+}
+
+```
+```typescript
+export interface AllowedAuditorInfo {
+ auditorBaseUrl: string;
+ auditorPub: string;
+}
+
+```
+```typescript
+export interface AllowedExchangeInfo {
+ exchangeBaseUrl: string;
+ exchangePub: string;
+}
+
+```
+
+### ConfirmPayOp
+```typescript
+/**
+ * Confirm a payment that was previously prepared with
+ * {@link PreparePayForUriOp}
+ */
+export type ConfirmPayOp = {
+ op: WalletApiOperation.ConfirmPay;
+ request: ConfirmPayRequest;
+ response: ConfirmPayResult;
+};
+// ConfirmPay = "confirmPay"
+
+```
+```typescript
+export interface ConfirmPayRequest {
+ proposalId: string;
+ sessionId?: string;
+ forcedCoinSel?: ForcedCoinSel;
+}
+
+```
+```typescript
+export type ConfirmPayResult = ConfirmPayResultDone | ConfirmPayResultPending;
+
+```
+```typescript
+/**
+ * Result for confirmPay
+ */
+export interface ConfirmPayResultDone {
+ type: ConfirmPayResultType.Done;
+ contractTerms: MerchantContractTerms;
+ transactionId: string;
+}
+
+```
+```typescript
+export interface ConfirmPayResultPending {
+ type: ConfirmPayResultType.Pending;
+ transactionId: string;
+ lastError: TalerErrorDetail | undefined;
+}
+
+```
+
+### ApplyRefundOp
+```typescript
+/**
+ * Check for a refund based on a taler://refund URI.
+ */
+export type ApplyRefundOp = {
+ op: WalletApiOperation.ApplyRefund;
+ request: ApplyRefundRequest;
+ response: ApplyRefundResponse;
+};
+// ApplyRefund = "applyRefund"
+
+```
+```typescript
+export interface ApplyRefundRequest {
+ talerRefundUri: string;
+}
+
+```
+
+### ApplyRefundFromPurchaseIdOp
+```typescript
+export type ApplyRefundFromPurchaseIdOp = {
+ op: WalletApiOperation.ApplyRefundFromPurchaseId;
+ request: ApplyRefundFromPurchaseIdRequest;
+ response: ApplyRefundResponse;
+};
+// ApplyRefundFromPurchaseId = "applyRefundFromPurchaseId"
+
+```
+```typescript
+export interface ApplyRefundFromPurchaseIdRequest {
+ purchaseId: string;
+}
+
+```
+
+### PrepareRefundOp
+```typescript
+export type PrepareRefundOp = {
+ op: WalletApiOperation.PrepareRefund;
+ request: PrepareRefundRequest;
+ response: PrepareRefundResult;
+};
+// PrepareRefund = "prepareRefund"
+
+```
+```typescript
+export interface PrepareRefundRequest {
+ talerRefundUri: string;
+}
+
+```
+```typescript
+export interface PrepareRefundResult {
+ proposalId: string;
+ effectivePaid: AmountString;
+ gone: AmountString;
+ granted: AmountString;
+ pending: boolean;
+ awaiting: AmountString;
+ info: OrderShortInfo;
+}
+
+```
+
+### PrepareTipOp
+```typescript
+/**
+ * Query and store information about a tip.
+ */
+export type PrepareTipOp = {
+ op: WalletApiOperation.PrepareTip;
+ request: PrepareTipRequest;
+ response: PrepareTipResult;
+};
+// PrepareTip = "prepareTip"
+
+```
+```typescript
+export interface PrepareTipRequest {
+ talerTipUri: string;
+}
+
+```
+```typescript
+export interface PrepareTipResult {
+ /**
+ * Unique ID for the tip assigned by the wallet.
+ * Typically different from the merchant-generated tip ID.
+ */
+ walletTipId: string;
+ /**
+ * Has the tip already been accepted?
+ */
+ accepted: boolean;
+ /**
+ * Amount that the merchant gave.
+ */
+ tipAmountRaw: AmountString;
+ /**
+ * Amount that arrived at the wallet.
+ * Might be lower than the raw amount due to fees.
+ */
+ tipAmountEffective: AmountString;
+ /**
+ * Base URL of the merchant backend giving then tip.
+ */
+ merchantBaseUrl: string;
+ /**
+ * Base URL of the exchange that is used to withdraw the tip.
+ * Determined by the merchant, the wallet/user has no choice here.
+ */
+ exchangeBaseUrl: string;
+ /**
+ * Time when the tip will expire. After it expired, it can't be picked
+ * up anymore.
+ */
+ expirationTimestamp: TalerProtocolTimestamp;
+}
+
+```
+
+### AcceptTipOp
+```typescript
+/**
+ * Accept a tip.
+ */
+export type AcceptTipOp = {
+ op: WalletApiOperation.AcceptTip;
+ request: AcceptTipRequest;
+ response: AcceptTipResponse;
+};
+// AcceptTip = "acceptTip"
+
+```
+```typescript
+export interface AcceptTipRequest {
+ walletTipId: string;
+}
+
+```
+```typescript
+export interface AcceptTipResponse {
+ transactionId: string;
+ next_url?: string;
+}
+
+```
+
+### ListExchangesOp
+```typescript
+/**
+ * List exchanges known to the wallet.
+ */
+export type ListExchangesOp = {
+ op: WalletApiOperation.ListExchanges;
+ request: EmptyObject;
+ response: ExchangesListResponse;
+};
+// ListExchanges = "listExchanges"
+
+```
+```typescript
+export interface ExchangesListResponse {
+ exchanges: ExchangeListItem[];
+}
+
+```
+
+### AddExchangeOp
+```typescript
+/**
+ * Add / force-update an exchange.
+ */
+export type AddExchangeOp = {
+ op: WalletApiOperation.AddExchange;
+ request: AddExchangeRequest;
+ response: EmptyObject;
+};
+// AddExchange = "addExchange"
+
+```
+
+### ListKnownBankAccountsOp
+```typescript
+export type ListKnownBankAccountsOp = {
+ op: WalletApiOperation.ListKnownBankAccounts;
+ request: ListKnownBankAccountsRequest;
+ response: KnownBankAccounts;
+};
+// ListKnownBankAccounts = "listKnownBankAccounts"
+
+```
+```typescript
+export interface ListKnownBankAccountsRequest {
+ currency?: string;
+}
+
+```
+```typescript
+export interface KnownBankAccounts {
+ accounts: KnownBankAccountsInfo[];
+}
+
+```
+```typescript
+export interface KnownBankAccountsInfo {
+ uri: PaytoUri;
+ kyc_completed: boolean;
+ currency: string;
+ alias: string;
+}
+
+```
+```typescript
+export type PaytoUri =
+ | PaytoUriUnknown
+ | PaytoUriIBAN
+ | PaytoUriTalerBank
+ | PaytoUriBitcoin;
+
+```
+```typescript
+export interface PaytoUriUnknown extends PaytoUriGeneric {
+ isKnown: false;
+}
+
+```
+```typescript
+export interface PaytoUriGeneric {
+ targetType: string;
+ targetPath: string;
+ params: {
+ [name: string]: string;
+ };
+}
+
+```
+```typescript
+export interface PaytoUriIBAN extends PaytoUriGeneric {
+ isKnown: true;
+ targetType: "iban";
+ iban: string;
+ bic?: string;
+}
+
+```
+```typescript
+export interface PaytoUriTalerBank extends PaytoUriGeneric {
+ isKnown: true;
+ targetType: "x-taler-bank";
+ host: string;
+ account: string;
+}
+
+```
+```typescript
+export interface PaytoUriBitcoin extends PaytoUriGeneric {
+ isKnown: true;
+ targetType: "bitcoin";
+ segwitAddrs: Array<string>;
+}
+
+```
+
+### AddKnownBankAccountsOp
+```typescript
+export type AddKnownBankAccountsOp = {
+ op: WalletApiOperation.AddKnownBankAccounts;
+ request: AddKnownBankAccountsRequest;
+ response: EmptyObject;
+};
+// AddKnownBankAccounts = "addKnownBankAccounts"
+
+```
+```typescript
+export interface AddKnownBankAccountsRequest {
+ payto: string;
+ alias: string;
+ currency: string;
+}
+
+```
+
+### ForgetKnownBankAccountsOp
+```typescript
+export type ForgetKnownBankAccountsOp = {
+ op: WalletApiOperation.ForgetKnownBankAccounts;
+ request: ForgetKnownBankAccountsRequest;
+ response: EmptyObject;
+};
+// ForgetKnownBankAccounts = "forgetKnownBankAccounts"
+
+```
+```typescript
+export interface ForgetKnownBankAccountsRequest {
+ payto: string;
+}
+
+```
+
+### SetExchangeTosAcceptedOp
+```typescript
+/**
+ * Accept a particular version of the exchange terms of service.
+ */
+export type SetExchangeTosAcceptedOp = {
+ op: WalletApiOperation.SetExchangeTosAccepted;
+ request: AcceptExchangeTosRequest;
+ response: EmptyObject;
+};
+// SetExchangeTosAccepted = "setExchangeTosAccepted"
+
+```
+```typescript
+export interface AcceptExchangeTosRequest {
+ exchangeBaseUrl: string;
+ etag: string | undefined;
+}
+
+```
+
+### GetExchangeTosOp
+```typescript
+/**
+ * Get the current terms of a service of an exchange.
+ */
+export type GetExchangeTosOp = {
+ op: WalletApiOperation.GetExchangeTos;
+ request: GetExchangeTosRequest;
+ response: GetExchangeTosResult;
+};
+// GetExchangeTos = "getExchangeTos"
+
+```
+```typescript
+export interface GetExchangeTosRequest {
+ exchangeBaseUrl: string;
+ acceptedFormat?: string[];
+}
+
+```
+```typescript
+export interface GetExchangeTosResult {
+ /**
+ * Markdown version of the current ToS.
+ */
+ content: string;
+ /**
+ * Version tag of the current ToS.
+ */
+ currentEtag: string;
+ /**
+ * Version tag of the last ToS that the user has accepted,
+ * if any.
+ */
+ acceptedEtag: string | undefined;
+ /**
+ * Accepted content type
+ */
+ contentType: string;
+ tosStatus: ExchangeTosStatus;
+}
+
+```
+
+### GetExchangeDetailedInfoOp
+```typescript
+/**
+ * Get the current terms of a service of an exchange.
+ */
+export type GetExchangeDetailedInfoOp = {
+ op: WalletApiOperation.GetExchangeDetailedInfo;
+ request: AddExchangeRequest;
+ response: ExchangeDetailedResponse;
+};
+// GetExchangeDetailedInfo = "getExchangeDetailedInfo"
+
+```
+```typescript
+export interface ExchangeDetailedResponse {
+ exchange: ExchangeFullDetails;
+}
+
+```
+```typescript
+export interface ExchangeFullDetails {
+ exchangeBaseUrl: string;
+ currency: string;
+ paytoUris: string[];
+ tos: ExchangeTosStatusDetails;
+ auditors: ExchangeAuditor[];
+ wireInfo: WireInfo;
+ denomFees: DenomOperationMap<FeeDescription[]>;
+ transferFees: Record<string, FeeDescription[]>;
+ globalFees: FeeDescription[];
+}
+
+```
+```typescript
+export interface ExchangeTosStatusDetails {
+ acceptedVersion?: string;
+ currentVersion?: string;
+ contentType?: string;
+ content?: string;
+}
+
+```
+```typescript
+export interface WireInfo {
+ feesForType: WireFeeMap;
+ accounts: ExchangeAccount[];
+}
+
+```
+```typescript
+/**
+ * Information about one of the exchange's bank accounts.
+ */
+export interface ExchangeAccount {
+ payto_uri: string;
+ master_sig: string;
+}
+
+```
+```typescript
+export interface FeeDescription {
+ group: string;
+ from: AbsoluteTime;
+ until: AbsoluteTime;
+ fee?: AmountString;
+}
+
+```
+
+### ListCurrenciesOp
+```typescript
+/**
+ * List currencies known to the wallet.
+ */
+export type ListCurrenciesOp = {
+ op: WalletApiOperation.ListCurrencies;
+ request: EmptyObject;
+ response: WalletCurrencyInfo;
+};
+// ListCurrencies = "listCurrencies"
+
+```
+```typescript
+export interface WalletCurrencyInfo {
+ trustedAuditors: {
+ currency: string;
+ auditorPub: string;
+ auditorBaseUrl: string;
+ }[];
+ trustedExchanges: {
+ currency: string;
+ exchangeMasterPub: string;
+ exchangeBaseUrl: string;
+ }[];
+}
+
+```
+
+### GenerateDepositGroupTxIdOp
+```typescript
+/**
+ * Generate a fresh transaction ID for a deposit group.
+ *
+ * The resulting transaction ID can be specified when creating
+ * a deposit group, so that the client can already start waiting for notifications
+ * on that specific deposit group before the GreateDepositGroup request returns.
+ */
+export type GenerateDepositGroupTxIdOp = {
+ op: WalletApiOperation.GenerateDepositGroupTxId;
+ request: EmptyObject;
+ response: TxIdResponse;
+};
+// GenerateDepositGroupTxId = "generateDepositGroupTxId"
+
+```
+```typescript
+export interface TxIdResponse {
+ transactionId: string;
+}
+
+```
+
+### CreateDepositGroupOp
+```typescript
+/**
+ * Create a new deposit group.
+ *
+ * Deposit groups are used to deposit multiple coins to a bank
+ * account, usually the wallet user's own bank account.
+ */
+export type CreateDepositGroupOp = {
+ op: WalletApiOperation.CreateDepositGroup;
+ request: CreateDepositGroupRequest;
+ response: CreateDepositGroupResponse;
+};
+// CreateDepositGroup = "createDepositGroup"
+
+```
+```typescript
+export interface CreateDepositGroupRequest {
+ /**
+ * Pre-allocated transaction ID.
+ * Allows clients to easily handle notifications
+ * that occur while the operation has been created but
+ * before the creation request has returned.
+ */
+ transactionId?: string;
+ depositPaytoUri: string;
+ amount: AmountString;
+}
+
+```
+```typescript
+export interface CreateDepositGroupResponse {
+ depositGroupId: string;
+ transactionId: string;
+}
+
+```
+
+### PrepareDepositOp
+```typescript
+export type PrepareDepositOp = {
+ op: WalletApiOperation.PrepareDeposit;
+ request: PrepareDepositRequest;
+ response: PrepareDepositResponse;
+};
+// PrepareDeposit = "prepareDeposit"
+
+```
+```typescript
+export interface PrepareDepositRequest {
+ depositPaytoUri: string;
+ amount: AmountString;
+}
+
+```
+```typescript
+export interface PrepareDepositResponse {
+ totalDepositCost: AmountString;
+ effectiveDepositAmount: AmountString;
+ fees: DepositGroupFees;
+}
+
+```
+```typescript
+export interface DepositGroupFees {
+ coin: AmountString;
+ wire: AmountString;
+ refresh: AmountString;
+}
+
+```
+
+### ExportBackupRecoveryOp
+```typescript
+/**
+ * Export the recovery information for the wallet.
+ */
+export type ExportBackupRecoveryOp = {
+ op: WalletApiOperation.ExportBackupRecovery;
+ request: EmptyObject;
+ response: BackupRecovery;
+};
+// ExportBackupRecovery = "exportBackupRecovery"
+
+```
+
+### ImportBackupRecoveryOp
+```typescript
+/**
+ * Import recovery information into the wallet.
+ */
+export type ImportBackupRecoveryOp = {
+ op: WalletApiOperation.ImportBackupRecovery;
+ request: RecoveryLoadRequest;
+ response: EmptyObject;
+};
+// ImportBackupRecovery = "importBackupRecovery"
+
+```
+```typescript
+/**
+ * Load recovery information into the wallet.
+ */
+export interface RecoveryLoadRequest {
+ recovery: BackupRecovery;
+ strategy?: RecoveryMergeStrategy;
+}
+
+```
+```typescript
+/**
+ * Strategy for loading recovery information.
+ */
+export declare enum RecoveryMergeStrategy {
+ /**
+ * Keep the local wallet root key, import and take over providers.
+ */
+ Ours = "ours",
+ /**
+ * Migrate to the wallet root key from the recovery information.
+ */
+ Theirs = "theirs",
+}
+
+```
+
+### RunBackupCycleOp
+```typescript
+/**
+ * Manually make and upload a backup.
+ */
+export type RunBackupCycleOp = {
+ op: WalletApiOperation.RunBackupCycle;
+ request: RunBackupCycleRequest;
+ response: EmptyObject;
+};
+// RunBackupCycle = "runBackupCycle"
+
+```
+```typescript
+export interface RunBackupCycleRequest {
+ /**
+ * List of providers to backup or empty for all known providers.
+ */
+ providers?: Array<string>;
+}
+
+```
+
+### ExportBackupOp
+```typescript
+export type ExportBackupOp = {
+ op: WalletApiOperation.ExportBackup;
+ request: EmptyObject;
+ response: EmptyObject;
+};
+// ExportBackup = "exportBackup"
+
+```
+
+### AddBackupProviderOp
+```typescript
+/**
+ * Add a new backup provider.
+ */
+export type AddBackupProviderOp = {
+ op: WalletApiOperation.AddBackupProvider;
+ request: AddBackupProviderRequest;
+ response: AddBackupProviderResponse;
+};
+// AddBackupProvider = "addBackupProvider"
+
+```
+```typescript
+export interface AddBackupProviderRequest {
+ backupProviderBaseUrl: string;
+ name: string;
+ /**
+ * Activate the provider. Should only be done after
+ * the user has reviewed the provider.
+ */
+ activate?: boolean;
+}
+
+```
+```typescript
+export type AddBackupProviderResponse =
+ | AddBackupProviderOk
+ | AddBackupProviderPaymentRequired;
+
+```
+```typescript
+interface AddBackupProviderOk {
+ status: "ok";
+}
+
+```
+```typescript
+interface AddBackupProviderPaymentRequired {
+ status: "payment-required";
+ talerUri?: string;
+}
+
+```
+
+### RemoveBackupProviderOp
+```typescript
+export type RemoveBackupProviderOp = {
+ op: WalletApiOperation.RemoveBackupProvider;
+ request: RemoveBackupProviderRequest;
+ response: EmptyObject;
+};
+// RemoveBackupProvider = "removeBackupProvider"
+
+```
+```typescript
+export interface RemoveBackupProviderRequest {
+ provider: string;
+}
+
+```
+
+### GetBackupInfoOp
+```typescript
+/**
+ * Get some useful stats about the backup state.
+ */
+export type GetBackupInfoOp = {
+ op: WalletApiOperation.GetBackupInfo;
+ request: EmptyObject;
+ response: BackupInfo;
+};
+// GetBackupInfo = "getBackupInfo"
+
+```
+```typescript
+export interface BackupInfo {
+ walletRootPub: string;
+ deviceId: string;
+ providers: ProviderInfo[];
+}
+
+```
+```typescript
+/**
+ * Information about one provider.
+ *
+ * We don't store the account key here,
+ * as that's derived from the wallet root key.
+ */
+export interface ProviderInfo {
+ active: boolean;
+ syncProviderBaseUrl: string;
+ name: string;
+ terms?: BackupProviderTerms;
+ /**
+ * Last communication issue with the provider.
+ */
+ lastError?: TalerErrorDetail;
+ lastSuccessfulBackupTimestamp?: TalerProtocolTimestamp;
+ lastAttemptedBackupTimestamp?: TalerProtocolTimestamp;
+ paymentProposalIds: string[];
+ backupProblem?: BackupProblem;
+ paymentStatus: ProviderPaymentStatus;
+}
+
+```
+```typescript
+export interface BackupProviderTerms {
+ supportedProtocolVersion: string;
+ annualFee: AmountString;
+ storageLimitInMegabytes: number;
+}
+
+```
+```typescript
+export type BackupProblem =
+ | BackupUnreadableProblem
+ | BackupConflictingDeviceProblem;
+
+```
+```typescript
+export interface BackupUnreadableProblem {
+ type: "backup-unreadable";
+}
+
+```
+```typescript
+export interface BackupConflictingDeviceProblem {
+ type: "backup-conflicting-device";
+ otherDeviceId: string;
+ myDeviceId: string;
+ backupTimestamp: AbsoluteTime;
+}
+
+```
+```typescript
+export type ProviderPaymentStatus =
+ | ProviderPaymentTermsChanged
+ | ProviderPaymentPaid
+ | ProviderPaymentInsufficientBalance
+ | ProviderPaymentUnpaid
+ | ProviderPaymentPending;
+
+```
+```typescript
+export interface ProviderPaymentTermsChanged {
+ type: ProviderPaymentType.TermsChanged;
+ paidUntil: AbsoluteTime;
+ oldTerms: BackupProviderTerms;
+ newTerms: BackupProviderTerms;
+}
+
+```
+```typescript
+export interface ProviderPaymentPaid {
+ type: ProviderPaymentType.Paid;
+ paidUntil: AbsoluteTime;
+}
+
+```
+```typescript
+export interface ProviderPaymentInsufficientBalance {
+ type: ProviderPaymentType.InsufficientBalance;
+ amount: AmountString;
+}
+
+```
+```typescript
+export interface ProviderPaymentUnpaid {
+ type: ProviderPaymentType.Unpaid;
+}
+
+```
+```typescript
+export interface ProviderPaymentPending {
+ type: ProviderPaymentType.Pending;
+ talerUri?: string;
+}
+
+```
+
+### SetWalletDeviceIdOp
+```typescript
+/**
+ * Set the internal device ID of the wallet, used to
+ * identify whether a different/new wallet is accessing
+ * the backup of another wallet.
+ */
+export type SetWalletDeviceIdOp = {
+ op: WalletApiOperation.SetWalletDeviceId;
+ request: SetWalletDeviceIdRequest;
+ response: EmptyObject;
+};
+// SetWalletDeviceId = "setWalletDeviceId"
+
+```
+```typescript
+export interface SetWalletDeviceIdRequest {
+ /**
+ * New wallet device ID to set.
+ */
+ walletDeviceId: string;
+}
+
+```
+
+### ExportBackupPlainOp
+```typescript
+/**
+ * Export a backup JSON, mostly useful for testing.
+ */
+export type ExportBackupPlainOp = {
+ op: WalletApiOperation.ExportBackupPlain;
+ request: EmptyObject;
+ response: WalletBackupContentV1;
+};
+// ExportBackupPlain = "exportBackupPlain"
+
+```
+
+### CheckPeerPushDebitOp
+```typescript
+/**
+ * Check if initiating a peer push payment is possible
+ * based on the funds in the wallet.
+ */
+export type CheckPeerPushDebitOp = {
+ op: WalletApiOperation.CheckPeerPushDebit;
+ request: CheckPeerPushDebitRequest;
+ response: CheckPeerPushDebitResponse;
+};
+// CheckPeerPushDebit = "checkPeerPushDebit"
+
+```
+```typescript
+export interface CheckPeerPushDebitRequest {
+ /**
+ * Preferred exchange to use for the p2p payment.
+ */
+ exchangeBaseUrl?: string;
+ /**
+ * Instructed amount.
+ *
+ * FIXME: Allow specifying the instructed amount type.
+ */
+ amount: AmountString;
+}
+
+```
+```typescript
+export interface CheckPeerPushDebitResponse {
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+}
+
+```
+
+### InitiatePeerPushDebitOp
+```typescript
+/**
+ * Initiate an outgoing peer push payment.
+ */
+export type InitiatePeerPushDebitOp = {
+ op: WalletApiOperation.InitiatePeerPushDebit;
+ request: InitiatePeerPushPaymentRequest;
+ response: InitiatePeerPushPaymentResponse;
+};
+// InitiatePeerPushDebit = "initiatePeerPushDebit"
+
+```
+```typescript
+export interface InitiatePeerPushPaymentRequest {
+ exchangeBaseUrl?: string;
+ partialContractTerms: PeerContractTerms;
+}
+
+```
+```typescript
+export interface InitiatePeerPushPaymentResponse {
+ exchangeBaseUrl: string;
+ pursePub: string;
+ mergePriv: string;
+ contractPriv: string;
+ talerUri: string;
+ transactionId: string;
+}
+
+```
+
+### PreparePeerPushCreditOp
+```typescript
+/**
+ * Check an incoming peer push payment.
+ */
+export type PreparePeerPushCreditOp = {
+ op: WalletApiOperation.PreparePeerPushCredit;
+ request: PreparePeerPushCredit;
+ response: PreparePeerPushCreditResponse;
+};
+// PreparePeerPushCredit = "preparePeerPushCredit"
+
+```
+```typescript
+export interface PreparePeerPushCreditResponse {
+ contractTerms: PeerContractTerms;
+ /**
+ * @deprecated
+ */
+ amount: AmountString;
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+ peerPushPaymentIncomingId: string;
+}
+
+```
+
+### ConfirmPeerPushCreditOp
+```typescript
+/**
+ * Accept an incoming peer push payment.
+ */
+export type ConfirmPeerPushCreditOp = {
+ op: WalletApiOperation.ConfirmPeerPushCredit;
+ request: ConfirmPeerPushCreditRequest;
+ response: EmptyObject;
+};
+// ConfirmPeerPushCredit = "confirmPeerPushCredit"
+
+```
+```typescript
+export interface ConfirmPeerPushCreditRequest {
+ /**
+ * Transparent identifier of the incoming peer push payment.
+ */
+ peerPushPaymentIncomingId: string;
+}
+
+```
+
+### CheckPeerPullCreditOp
+```typescript
+/**
+ * Check fees for an outgoing peer pull payment.
+ */
+export type CheckPeerPullCreditOp = {
+ op: WalletApiOperation.CheckPeerPullCredit;
+ request: CheckPeerPullCreditRequest;
+ response: CheckPeerPullCreditResponse;
+};
+// CheckPeerPullCredit = "checkPeerPullCredit"
+
+```
+```typescript
+export interface CheckPeerPullCreditRequest {
+ exchangeBaseUrl?: string;
+ amount: AmountString;
+}
+
+```
+```typescript
+export interface CheckPeerPullCreditResponse {
+ exchangeBaseUrl: string;
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+}
+
+```
+
+### InitiatePeerPullCreditOp
+```typescript
+/**
+ * Initiate an outgoing peer pull payment.
+ */
+export type InitiatePeerPullCreditOp = {
+ op: WalletApiOperation.InitiatePeerPullCredit;
+ request: InitiatePeerPullCreditRequest;
+ response: InitiatePeerPullCreditResponse;
+};
+// InitiatePeerPullCredit = "initiatePeerPullCredit"
+
+```
+```typescript
+export interface InitiatePeerPullCreditRequest {
+ exchangeBaseUrl?: string;
+ partialContractTerms: PeerContractTerms;
+}
+
+```
+```typescript
+export interface InitiatePeerPullCreditResponse {
+ /**
+ * Taler URI for the other party to make the payment
+ * that was requested.
+ */
+ talerUri: string;
+ transactionId: string;
+}
+
+```
+
+### PreparePeerPullDebitOp
+```typescript
+/**
+ * Prepare for an incoming peer pull payment.
+ */
+export type PreparePeerPullDebitOp = {
+ op: WalletApiOperation.PreparePeerPullDebit;
+ request: PreparePeerPullDebitRequest;
+ response: PreparePeerPullDebitResponse;
+};
+// PreparePeerPullDebit = "preparePeerPullDebit"
+
+```
+```typescript
+export interface PreparePeerPullDebitRequest {
+ talerUri: string;
+}
+
+```
+```typescript
+export interface PreparePeerPullDebitResponse {
+ contractTerms: PeerContractTerms;
+ /**
+ * @deprecated Redundant field with bad name, will be removed soon.
+ */
+ amount: AmountString;
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+ peerPullPaymentIncomingId: string;
+}
+
+```
+
+### ConfirmPeerPullDebitOp
+```typescript
+/**
+ * Accept an incoming peer pull payment (i.e. pay the other party).
+ */
+export type ConfirmPeerPullDebitOp = {
+ op: WalletApiOperation.ConfirmPeerPullDebit;
+ request: ConfirmPeerPullDebitRequest;
+ response: EmptyObject;
+};
+// ConfirmPeerPullDebit = "confirmPeerPullDebit"
+
+```
+```typescript
+export interface ConfirmPeerPullDebitRequest {
+ /**
+ * Transparent identifier of the incoming peer pull payment.
+ */
+ peerPullPaymentIncomingId: string;
+}
+
+```
+
+### ValidateIbanOp
+```typescript
+export type ValidateIbanOp = {
+ op: WalletApiOperation.ValidateIban;
+ request: ValidateIbanRequest;
+ response: ValidateIbanResponse;
+};
+// ValidateIban = "validateIban"
+
+```
+```typescript
+export interface ValidateIbanRequest {
+ iban: string;
+}
+
+```
+```typescript
+export interface ValidateIbanResponse {
+ valid: boolean;
+}
+
+```
+
+### ExportDbOp
+```typescript
+/**
+ * Export the wallet database's contents to JSON.
+ */
+export type ExportDbOp = {
+ op: WalletApiOperation.ExportDb;
+ request: EmptyObject;
+ response: any;
+};
+// ExportDb = "exportDb"
+
+```
+
+### ImportDbOp
+```typescript
+export type ImportDbOp = {
+ op: WalletApiOperation.ImportDb;
+ request: any;
+ response: any;
+};
+// ImportDb = "importDb"
+
+```
+
+### ClearDbOp
+```typescript
+/**
+ * Dangerously clear the whole wallet database.
+ */
+export type ClearDbOp = {
+ op: WalletApiOperation.ClearDb;
+ request: EmptyObject;
+ response: EmptyObject;
+};
+// ClearDb = "clearDb"
+
+```
+
+### RecycleOp
+```typescript
+/**
+ * Export a backup, clear the database and re-import it.
+ */
+export type RecycleOp = {
+ op: WalletApiOperation.Recycle;
+ request: EmptyObject;
+ response: EmptyObject;
+};
+// Recycle = "recycle"
+
+```
+
+### ApplyDevExperimentOp
+```typescript
+/**
+ * Apply a developer experiment to the current wallet state.
+ *
+ * This allows UI developers / testers to play around without
+ * an elaborate test environment.
+ */
+export type ApplyDevExperimentOp = {
+ op: WalletApiOperation.ApplyDevExperiment;
+ request: ApplyDevExperimentRequest;
+ response: EmptyObject;
+};
+// ApplyDevExperiment = "applyDevExperiment"
+
+```
+```typescript
+export interface ApplyDevExperimentRequest {
+ devExperimentUri: string;
+}
+
+```
+
+### RunIntegrationTestOp
+```typescript
+/**
+ * Run a simple integration test on a test deployment
+ * of the exchange and merchant.
+ */
+export type RunIntegrationTestOp = {
+ op: WalletApiOperation.RunIntegrationTest;
+ request: IntegrationTestArgs;
+ response: EmptyObject;
+};
+// RunIntegrationTest = "runIntegrationTest"
+
+```
+
+### RunIntegrationTestV2Op
+```typescript
+/**
+ * Run a simple integration test on a test deployment
+ * of the exchange and merchant.
+ */
+export type RunIntegrationTestV2Op = {
+ op: WalletApiOperation.RunIntegrationTestV2;
+ request: IntegrationTestArgs;
+ response: EmptyObject;
+};
+// RunIntegrationTestV2 = "runIntegrationTestV2"
+
+```
+
+### TestCryptoOp
+```typescript
+/**
+ * Test crypto worker.
+ */
+export type TestCryptoOp = {
+ op: WalletApiOperation.TestCrypto;
+ request: EmptyObject;
+ response: any;
+};
+// TestCrypto = "testCrypto"
+
+```
+
+### WithdrawTestBalanceOp
+```typescript
+/**
+ * Make withdrawal on a test deployment of the exchange
+ * and merchant.
+ */
+export type WithdrawTestBalanceOp = {
+ op: WalletApiOperation.WithdrawTestBalance;
+ request: WithdrawTestBalanceRequest;
+ response: EmptyObject;
+};
+// WithdrawTestBalance = "withdrawTestBalance"
+
+```
+```typescript
+export interface WithdrawTestBalanceRequest {
+ amount: string;
+ /**
+ * Bank access API base URL.
+ */
+ bankAccessApiBaseUrl: string;
+ exchangeBaseUrl: string;
+ forcedDenomSel?: ForcedDenomSel;
+}
+
+```
+
+### WithdrawTestkudosOp
+```typescript
+/**
+ * Make a withdrawal of testkudos on test.taler.net.
+ */
+export type WithdrawTestkudosOp = {
+ op: WalletApiOperation.WithdrawTestkudos;
+ request: EmptyObject;
+ response: EmptyObject;
+};
+// WithdrawTestkudos = "withdrawTestkudos"
+
+```
+
+### TestPayOp
+```typescript
+/**
+ * Make a test payment using a test deployment of
+ * the exchange and merchant.
+ */
+export type TestPayOp = {
+ op: WalletApiOperation.TestPay;
+ request: TestPayArgs;
+ response: TestPayResult;
+};
+// TestPay = "testPay"
+
+```
+```typescript
+export interface TestPayArgs {
+ merchantBaseUrl: string;
+ merchantAuthToken?: string;
+ amount: string;
+ summary: string;
+ forcedCoinSel?: ForcedCoinSel;
+}
+
+```
+```typescript
+export interface TestPayResult {
+ payCoinSelection: PayCoinSelection;
+}
+
+```
+```typescript
+/**
+ * Result of selecting coins, contains the exchange, and selected
+ * coins with their denomination.
+ */
+export interface PayCoinSelection {
+ /**
+ * Amount requested by the merchant.
+ */
+ paymentAmount: AmountString;
+ /**
+ * Public keys of the coins that were selected.
+ */
+ coinPubs: string[];
+ /**
+ * Amount that each coin contributes.
+ */
+ coinContributions: AmountString[];
+ /**
+ * How much of the wire fees is the customer paying?
+ */
+ customerWireFees: AmountString;
+ /**
+ * How much of the deposit fees is the customer paying?
+ */
+ customerDepositFees: AmountString;
+}
+
+```
+
+### WithdrawFakebankOp
+```typescript
+/**
+ * Make a withdrawal from a fakebank, i.e.
+ * a bank where test users can be registered freely
+ * and testing APIs are available.
+ */
+export type WithdrawFakebankOp = {
+ op: WalletApiOperation.WithdrawFakebank;
+ request: WithdrawFakebankRequest;
+ response: EmptyObject;
+};
+// WithdrawFakebank = "withdrawFakebank"
+
+```
+```typescript
+export interface WithdrawFakebankRequest {
+ amount: AmountString;
+ exchange: string;
+ bank: string;
+}
+
+```
+
+### GetPendingTasksOp
+```typescript
+/**
+ * Get wallet-internal pending tasks.
+ */
+export type GetPendingTasksOp = {
+ op: WalletApiOperation.GetPendingOperations;
+ request: EmptyObject;
+ response: PendingTasksResponse;
+};
+// GetPendingOperations = "getPendingOperations"
+
+```
+```typescript
+/**
+ * Response returned from the pending operations API.
+ */
+export interface PendingOperationsResponse {
+ /**
+ * List of pending operations.
+ */
+ pendingOperations: PendingTaskInfo[];
+}
+
+```
+```typescript
+/**
+ * Information about a pending operation.
+ */
+export type PendingTaskInfo = PendingTaskInfoCommon &
+ (
+ | PendingExchangeUpdateTask
+ | PendingExchangeCheckRefreshTask
+ | PendingPurchaseTask
+ | PendingRefreshTask
+ | PendingTipPickupTask
+ | PendingWithdrawTask
+ | PendingRecoupTask
+ | PendingDepositTask
+ | PendingBackupTask
+ | PendingPeerPushInitiationTask
+ | PendingPeerPullInitiationTask
+ | PendingPeerPullDebitTask
+ | PendingPeerPushCreditTask
+ );
+
+```
+```typescript
+/**
+ * Fields that are present in every pending operation.
+ */
+export interface PendingTaskInfoCommon {
+ /**
+ * Type of the pending operation.
+ */
+ type: PendingTaskType;
+ /**
+ * Unique identifier for the pending task.
+ */
+ id: string;
+ /**
+ * Set to true if the operation indicates that something is really in progress,
+ * as opposed to some regular scheduled operation that can be tried later.
+ */
+ givesLifeness: boolean;
+ /**
+ * Operation is active and waiting for a longpoll result.
+ */
+ isLongpolling: boolean;
+ /**
+ * Operation is waiting to be executed.
+ */
+ isDue: boolean;
+ /**
+ * Timestamp when the pending operation should be executed next.
+ */
+ timestampDue: AbsoluteTime;
+ /**
+ * Retry info. Currently used to stop the wallet after any operation
+ * exceeds a number of retries.
+ */
+ retryInfo?: RetryInfo;
+}
+
+```
+```typescript
+export enum PendingTaskType {
+ ExchangeUpdate = "exchange-update",
+ ExchangeCheckRefresh = "exchange-check-refresh",
+ Purchase = "purchase",
+ Refresh = "refresh",
+ Recoup = "recoup",
+ TipPickup = "tip-pickup",
+ Withdraw = "withdraw",
+ Deposit = "deposit",
+ Backup = "backup",
+ // FIXME: Rename to peer-push-debit and peer-pull-debit
+ PeerPushInitiation = "peer-push-initiation",
+ PeerPullInitiation = "peer-pull-initiation",
+ PeerPushCredit = "peer-push-credit",
+ PeerPullDebit = "peer-pull-debit",
+}
+
+```
+```typescript
+export interface RetryInfo {
+ firstTry: AbsoluteTime;
+ nextRetry: AbsoluteTime;
+ retryCounter: number;
+}
+
+```
+```typescript
+export interface RetryPolicy {
+ readonly backoffDelta: Duration;
+ readonly backoffBase: number;
+ readonly maxTimeout: Duration;
+}
+
+```
+```typescript
+// Declare "static" methods in Error
+interface ErrorConstructor {
+ /** Create .stack property on a target object */
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
+ /**
+ * Optional override for formatting stack traces
+ *
+ * @see https://v8.dev/docs/stack-trace-api#customizing-stack-traces
+ */
+ prepareStackTrace?:
+ | ((err: Error, stackTraces: NodeJS.CallSite[]) => any)
+ | undefined;
+ stackTraceLimit: number;
+}
+
+```
+```typescript
+interface CallSite {
+ /**
+ * Value of "this"
+ */
+ getThis(): unknown;
+ /**
+ * Type of "this" as a string.
+ * This is the name of the function stored in the constructor field of
+ * "this", if available. Otherwise the object's [[Class]] internal
+ * property.
+ */
+ getTypeName(): string | null;
+ /**
+ * Current function
+ */
+ getFunction(): Function | undefined;
+ /**
+ * Name of the current function, typically its name property.
+ * If a name property is not available an attempt will be made to try
+ * to infer a name from the function's context.
+ */
+ getFunctionName(): string | null;
+ /**
+ * Name of the property [of "this" or one of its prototypes] that holds
+ * the current function
+ */
+ getMethodName(): string | null;
+ /**
+ * Name of the script [if this function was defined in a script]
+ */
+ getFileName(): string | null;
+ /**
+ * Current line number [if this function was defined in a script]
+ */
+ getLineNumber(): number | null;
+ /**
+ * Current column number [if this function was defined in a script]
+ */
+ getColumnNumber(): number | null;
+ /**
+ * A call site object representing the location where eval was called
+ * [if this function was created using a call to eval]
+ */
+ getEvalOrigin(): string | undefined;
+ /**
+ * Is this a toplevel invocation, that is, is "this" the global object?
+ */
+ isToplevel(): boolean;
+ /**
+ * Does this call take place in code defined by a call to eval?
+ */
+ isEval(): boolean;
+ /**
+ * Is this call in native V8 code?
+ */
+ isNative(): boolean;
+ /**
+ * Is this a constructor call?
+ */
+ isConstructor(): boolean;
+}
+
+```
+```typescript
+/**
+ * The wallet is currently updating information about an exchange.
+ */
+export interface PendingExchangeUpdateTask {
+ type: PendingTaskType.ExchangeUpdate;
+ exchangeBaseUrl: string;
+ lastError: TalerErrorDetail | undefined;
+}
+
+```
+```typescript
+/**
+ * The wallet should check whether coins from this exchange
+ * need to be auto-refreshed.
+ */
+export interface PendingExchangeCheckRefreshTask {
+ type: PendingTaskType.ExchangeCheckRefresh;
+ exchangeBaseUrl: string;
+}
+
+```
+```typescript
+/**
+ * A purchase needs to be processed (i.e. for download / payment / refund).
+ */
+export interface PendingPurchaseTask {
+ type: PendingTaskType.Purchase;
+ proposalId: string;
+ retryInfo?: RetryInfo;
+ /**
+ * Status of the payment as string, used only for debugging.
+ */
+ statusStr: string;
+ lastError: TalerErrorDetail | undefined;
+}
+
+```
+```typescript
+/**
+ * Status of an ongoing withdrawal operation.
+ */
+export interface PendingRefreshTask {
+ type: PendingTaskType.Refresh;
+ lastError?: TalerErrorDetail;
+ refreshGroupId: string;
+ finishedPerCoin: boolean[];
+ retryInfo?: RetryInfo;
+}
+
+```
+```typescript
+/**
+ * The wallet is picking up a tip that the user has accepted.
+ */
+export interface PendingTipPickupTask {
+ type: PendingTaskType.TipPickup;
+ tipId: string;
+ merchantBaseUrl: string;
+ merchantTipId: string;
+}
+
+```
+```typescript
+/**
+ * Status of an ongoing withdrawal operation.
+ */
+export interface PendingWithdrawTask {
+ type: PendingTaskType.Withdraw;
+ lastError: TalerErrorDetail | undefined;
+ retryInfo?: RetryInfo;
+ withdrawalGroupId: string;
+}
+
+```
+```typescript
+export interface PendingRecoupTask {
+ type: PendingTaskType.Recoup;
+ recoupGroupId: string;
+ retryInfo?: RetryInfo;
+ lastError: TalerErrorDetail | undefined;
+}
+
+```
+```typescript
+/**
+ * Status of an ongoing deposit operation.
+ */
+export interface PendingDepositTask {
+ type: PendingTaskType.Deposit;
+ lastError: TalerErrorDetail | undefined;
+ retryInfo: RetryInfo | undefined;
+ depositGroupId: string;
+}
+
+```
+```typescript
+export interface PendingBackupTask {
+ type: PendingTaskType.Backup;
+ backupProviderBaseUrl: string;
+ lastError: TalerErrorDetail | undefined;
+}
+
+```
+```typescript
+/**
+ * The wallet wants to send a peer push payment.
+ */
+export interface PendingPeerPushInitiationTask {
+ type: PendingTaskType.PeerPushInitiation;
+ pursePub: string;
+}
+
+```
+```typescript
+/**
+ * The wallet wants to send a peer pull payment.
+ */
+export interface PendingPeerPullInitiationTask {
+ type: PendingTaskType.PeerPullInitiation;
+ pursePub: string;
+}
+
+```
+```typescript
+/**
+ * The wallet wants to send a peer pull payment.
+ */
+export interface PendingPeerPullDebitTask {
+ type: PendingTaskType.PeerPullDebit;
+ peerPullPaymentIncomingId: string;
+}
+
+```
+```typescript
+/**
+ */
+export interface PendingPeerPushCreditTask {
+ type: PendingTaskType.PeerPushCredit;
+ peerPushPaymentIncomingId: string;
+}
+
+```
+
+### DumpCoinsOp
+```typescript
+/**
+ * Dump all coins of the wallet in a simple JSON format.
+ */
+export type DumpCoinsOp = {
+ op: WalletApiOperation.DumpCoins;
+ request: EmptyObject;
+ response: CoinDumpJson;
+};
+// DumpCoins = "dumpCoins"
+
+```
+```typescript
+/**
+ * Easy to process format for the public data of coins
+ * managed by the wallet.
+ */
+export interface CoinDumpJson {
+ coins: Array<{
+ /**
+ * The coin's denomination's public key.
+ */
+ denom_pub: DenominationPubKey;
+ /**
+ * Hash of denom_pub.
+ */
+ denom_pub_hash: string;
+ /**
+ * Value of the denomination (without any fees).
+ */
+ denom_value: string;
+ /**
+ * Public key of the coin.
+ */
+ coin_pub: string;
+ /**
+ * Base URL of the exchange for the coin.
+ */
+ exchange_base_url: string;
+ /**
+ * Public key of the parent coin.
+ * Only present if this coin was obtained via refreshing.
+ */
+ refresh_parent_coin_pub: string | undefined;
+ /**
+ * Public key of the reserve for this coin.
+ * Only present if this coin was obtained via refreshing.
+ */
+ withdrawal_reserve_pub: string | undefined;
+ coin_status: CoinStatus;
+ spend_allocation:
+ | {
+ id: string;
+ amount: string;
+ }
+ | undefined;
+ /**
+ * Information about the age restriction
+ */
+ ageCommitmentProof: AgeCommitmentProof | undefined;
+ }>;
+}
+
+```
+```typescript
+export type DenominationPubKey = RsaDenominationPubKey | CsDenominationPubKey;
+
+```
+```typescript
+export interface RsaDenominationPubKey {
+ readonly cipher: DenomKeyType.Rsa;
+ readonly rsa_public_key: string;
+ readonly age_mask: number;
+}
+
+```
+```typescript
+export interface CsDenominationPubKey {
+ readonly cipher: DenomKeyType.ClauseSchnorr;
+ readonly age_mask: number;
+ readonly cs_public_key: string;
+}
+
+```
+```typescript
+/**
+ * Status of a coin.
+ */
+export declare enum CoinStatus {
+ /**
+ * Withdrawn and never shown to anybody.
+ */
+ Fresh = "fresh",
+ /**
+ * Fresh, but currently marked as "suspended", thus won't be used
+ * for spending. Used for testing.
+ */
+ FreshSuspended = "fresh-suspended",
+ /**
+ * A coin that has been spent and refreshed.
+ */
+ Dormant = "dormant",
+}
+
+```
+```typescript
+export interface AgeCommitmentProof {
+ commitment: AgeCommitment;
+ proof: AgeProof;
+}
+
+```
+```typescript
+export interface AgeCommitment {
+ mask: number;
+ /**
+ * Public keys, one for each age group specified in the age mask.
+ */
+ publicKeys: Edx25519PublicKeyEnc[];
+}
+
+```
+```typescript
+export type Edx25519PublicKeyEnc = FlavorP<string, "Edx25519PublicKeyEnc", 32>;
+
+```
+```typescript
+export type FlavorP<T, FlavorT extends string, S extends number> = T & {
+ _flavor?: `taler.${FlavorT}`;
+ _size?: S;
+};
+
+```
+```typescript
+export interface AgeProof {
+ /**
+ * Private keys. Typically smaller than the number of public keys,
+ * because we drop private keys from age groups that are restricted.
+ */
+ privateKeys: Edx25519PrivateKeyEnc[];
+}
+
+```
+```typescript
+export type Edx25519PrivateKeyEnc = FlavorP<
+ string,
+ "Edx25519PrivateKeyEnc",
+ 64
+>;
+
+```
+
+### SetCoinSuspendedOp
+```typescript
+/**
+ * Set a coin as (un-)suspended.
+ * Suspended coins won't be used for payments.
+ */
+export type SetCoinSuspendedOp = {
+ op: WalletApiOperation.SetCoinSuspended;
+ request: SetCoinSuspendedRequest;
+ response: EmptyObject;
+};
+// SetCoinSuspended = "setCoinSuspended"
+
+```
+```typescript
+export interface SetCoinSuspendedRequest {
+ coinPub: string;
+ suspended: boolean;
+}
+
+```
+
+### ForceRefreshOp
+```typescript
+/**
+ * Force a refresh on coins where it would not
+ * be necessary.
+ */
+export type ForceRefreshOp = {
+ op: WalletApiOperation.ForceRefresh;
+ request: ForceRefreshRequest;
+ response: EmptyObject;
+};
+// ForceRefresh = "forceRefresh"
+
+```
+```typescript
+export interface ForceRefreshRequest {
+ coinPubList: string[];
+}
+
+```
+
+## Common Declarations
+```typescript
+export interface WalletCoreVersion {
+ hash: string | undefined;
+ version: string;
+ exchange: string;
+ merchant: string;
+ bank: string;
+ /**
+ * @deprecated will be removed
+ */
+ devMode: boolean;
+}
+```
+```typescript
+export type Transaction =
+ | TransactionWithdrawal
+ | TransactionPayment
+ | TransactionRefund
+ | TransactionTip
+ | TransactionRefresh
+ | TransactionDeposit
+ | TransactionPeerPullCredit
+ | TransactionPeerPullDebit
+ | TransactionPeerPushCredit
+ | TransactionPeerPushDebit;
+```
+```typescript
+export interface TransactionWithdrawal extends TransactionCommon {
+ type: TransactionType.Withdrawal;
+ /**
+ * Exchange of the withdrawal.
+ */
+ exchangeBaseUrl: string;
+ /**
+ * Amount that got subtracted from the reserve balance.
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount that actually was (or will be) added to the wallet's balance.
+ */
+ amountEffective: AmountString;
+ withdrawalDetails: WithdrawalDetails;
+}
+```
+```typescript
+export interface TransactionCommon {
+ transactionId: TransactionIdStr;
+ type: TransactionType;
+ timestamp: TalerProtocolTimestamp;
+ /**
+ * Transaction state, as per DD37.
+ */
+ txState: TransactionState;
+ /**
+ * @deprecated in favor of statusMajor and statusMinor
+ */
+ extendedStatus: ExtendedStatus;
+ /**
+ * true if the transaction is still pending, false otherwise
+ * If a transaction is not longer pending, its timestamp will be updated,
+ * but its transactionId will remain unchanged
+ *
+ * @deprecated show extendedStatus
+ */
+ pending: boolean;
+ /**
+ * True if the transaction encountered a problem that might be
+ * permanent. A frozen transaction won't be automatically retried.
+ *
+ * @deprecated show extendedStatus
+ */
+ frozen: boolean;
+ /**
+ * Raw amount of the transaction (exclusive of fees or other extra costs).
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount added or removed from the wallet's balance (including all fees and other costs).
+ */
+ amountEffective: AmountString;
+ error?: TalerErrorDetail;
+}
+```
+```typescript
+export declare enum TransactionType {
+ Withdrawal = "withdrawal",
+ Payment = "payment",
+ Refund = "refund",
+ Refresh = "refresh",
+ Tip = "tip",
+ Deposit = "deposit",
+ PeerPushDebit = "peer-push-debit",
+ PeerPushCredit = "peer-push-credit",
+ PeerPullDebit = "peer-pull-debit",
+ PeerPullCredit = "peer-pull-credit",
+}
+```
+```typescript
+export interface TalerProtocolTimestamp {
+ readonly t_s: number | "never";
+}
+```
+```typescript
+export interface TransactionState {
+ major: TransactionMajorState;
+ minor?: TransactionMinorState;
+}
+```
+```typescript
+export declare enum TransactionMajorState {
+ None = "none",
+ Pending = "pending",
+ Done = "done",
+ Aborting = "aborting",
+ Aborted = "aborted",
+ Suspended = "suspended",
+ Failed = "failed",
+ Deleted = "deleted",
+ Unknown = "unknown",
+}
+```
+```typescript
+export declare enum TransactionMinorState {
+ Unknown = "unknown",
+ Deposit = "deposit",
+ KycRequired = "kyc-required",
+ Track = "track",
+ Refresh = "refresh",
+}
+```
+```typescript
+export declare enum ExtendedStatus {
+ Pending = "pending",
+ Done = "done",
+ Aborting = "aborting",
+ Aborted = "aborted",
+ Failed = "failed",
+ KycRequired = "kyc-required",
+}
+```
+```typescript
+export interface TalerErrorDetail {
+ code: TalerErrorCode;
+ when?: AbsoluteTime;
+ hint?: string;
+ [x: string]: unknown;
+}
+```
+```typescript
+export interface AbsoluteTime {
+ /**
+ * Timestamp in milliseconds.
+ */
+ readonly t_ms: number | "never";
+}
+```
+```typescript
+export interface Duration {
+ /**
+ * Duration in milliseconds.
+ */
+ readonly d_ms: number | "forever";
+}
+```
+```typescript
+export interface TalerProtocolDuration {
+ readonly d_us: number | "forever";
+}
+```
+```typescript
+export type WithdrawalDetails =
+ | WithdrawalDetailsForManualTransfer
+ | WithdrawalDetailsForTalerBankIntegrationApi;
+```
+```typescript
+interface WithdrawalDetailsForManualTransfer {
+ type: WithdrawalType.ManualTransfer;
+ /**
+ * Payto URIs that the exchange supports.
+ *
+ * Already contains the amount and message.
+ */
+ exchangePaytoUris: string[];
+ reservePub: string;
+ /**
+ * Is the reserve ready for withdrawal?
+ */
+ reserveIsReady: boolean;
+}
+```
+```typescript
+interface WithdrawalDetailsForTalerBankIntegrationApi {
+ type: WithdrawalType.TalerBankIntegrationApi;
+ /**
+ * Set to true if the bank has confirmed the withdrawal, false if not.
+ * An unconfirmed withdrawal usually requires user-input and should be highlighted in the UI.
+ * See also bankConfirmationUrl below.
+ */
+ confirmed: boolean;
+ /**
+ * If the withdrawal is unconfirmed, this can include a URL for user
+ * initiated confirmation.
+ */
+ bankConfirmationUrl?: string;
+ reservePub: string;
+ /**
+ * Is the reserve ready for withdrawal?
+ */
+ reserveIsReady: boolean;
+}
+```
+```typescript
+export interface TransactionPayment extends TransactionCommon {
+ type: TransactionType.Payment;
+ /**
+ * Additional information about the payment.
+ */
+ info: OrderShortInfo;
+ /**
+ * Wallet-internal end-to-end identifier for the payment.
+ */
+ proposalId: string;
+ /**
+ * How far did the wallet get with processing the payment?
+ *
+ * @deprecated use extendedStatus
+ */
+ status: PaymentStatus;
+ /**
+ * Amount that must be paid for the contract
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount that was paid, including deposit, wire and refresh fees.
+ */
+ amountEffective: AmountString;
+ /**
+ * Amount that has been refunded by the merchant
+ */
+ totalRefundRaw: AmountString;
+ /**
+ * Amount will be added to the wallet's balance after fees and refreshing
+ */
+ totalRefundEffective: AmountString;
+ /**
+ * Amount pending to be picked up
+ */
+ refundPending: AmountString | undefined;
+ /**
+ * Reference to applied refunds
+ */
+ refunds: RefundInfoShort[];
+ /**
+ * Is the wallet currently checking for a refund?
+ */
+ refundQueryActive: boolean;
+ /**
+ * Does this purchase has an pos validation
+ */
+ posConfirmation: string | undefined;
+}
+```
+```typescript
+export interface OrderShortInfo {
+ /**
+ * Order ID, uniquely identifies the order within a merchant instance
+ */
+ orderId: string;
+ /**
+ * Hash of the contract terms.
+ */
+ contractTermsHash: string;
+ /**
+ * More information about the merchant
+ */
+ merchant: MerchantInfo;
+ /**
+ * Summary of the order, given by the merchant
+ */
+ summary: string;
+ /**
+ * Map from IETF BCP 47 language tags to localized summaries
+ */
+ summary_i18n?: InternationalizedString;
+ /**
+ * List of products that are part of the order
+ */
+ products: Product[] | undefined;
+ /**
+ * Time indicating when the order should be delivered.
+ * May be overwritten by individual products.
+ */
+ delivery_date?: TalerProtocolTimestamp;
+ /**
+ * Delivery location for (all!) products.
+ */
+ delivery_location?: Location;
+ /**
+ * URL of the fulfillment, given by the merchant
+ */
+ fulfillmentUrl?: string;
+ /**
+ * Plain text message that should be shown to the user
+ * when the payment is complete.
+ */
+ fulfillmentMessage?: string;
+ /**
+ * Translations of fulfillmentMessage.
+ */
+ fulfillmentMessage_i18n?: InternationalizedString;
+}
+```
+```typescript
+export interface MerchantInfo {
+ name: string;
+ jurisdiction?: Location;
+ address?: Location;
+ logo?: string;
+ website?: string;
+ email?: string;
+}
+```
+```typescript
+export interface Location {
+ country?: string;
+ country_subdivision?: string;
+ district?: string;
+ town?: string;
+ town_location?: string;
+ post_code?: string;
+ street?: string;
+ building_name?: string;
+ building_number?: string;
+ address_lines?: string[];
+}
+```
+```typescript
+export interface InternationalizedString {
+ [lang_tag: string]: string;
+}
+```
+```typescript
+export interface Product {
+ product_id?: string;
+ description: string;
+ description_i18n?: {
+ [lang_tag: string]: string;
+ };
+ quantity?: number;
+ unit?: string;
+ price?: AmountString;
+ image?: string;
+ taxes?: Tax[];
+ delivery_date?: TalerProtocolTimestamp;
+}
+```
+```typescript
+export interface Tax {
+ name: string;
+ tax: AmountString;
+}
+```
+```typescript
+export declare enum PaymentStatus {
+ /**
+ * Explicitly aborted after timeout / failure
+ */
+ Aborted = "aborted",
+ /**
+ * Payment failed, wallet will auto-retry.
+ * User should be given the option to retry now / abort.
+ */
+ Failed = "failed",
+ /**
+ * Paid successfully
+ */
+ Paid = "paid",
+ /**
+ * User accepted, payment is processing.
+ */
+ Accepted = "accepted",
+}
+```
+```typescript
+export interface RefundInfoShort {
+ transactionId: string;
+ timestamp: TalerProtocolTimestamp;
+ amountEffective: AmountString;
+ amountRaw: AmountString;
+}
+```
+```typescript
+export interface TransactionRefund extends TransactionCommon {
+ type: TransactionType.Refund;
+ refundedTransactionId: string;
+ info: OrderShortInfo;
+ /**
+ * Amount pending to be picked up
+ */
+ refundPending: AmountString | undefined;
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+}
+```
+```typescript
+export interface TransactionTip extends TransactionCommon {
+ type: TransactionType.Tip;
+ amountRaw: AmountString;
+ /**
+ * More information about the merchant
+ */
+ amountEffective: AmountString;
+ merchantBaseUrl: string;
+}
+```
+```typescript
+/**
+ * A transaction shown for refreshes.
+ * Only shown for (1) refreshes not associated with other transactions
+ * and (2) refreshes in an error state.
+ */
+export interface TransactionRefresh extends TransactionCommon {
+ type: TransactionType.Refresh;
+ refreshReason: RefreshReason;
+ /**
+ * Transaction ID that caused this refresh.
+ */
+ originatingTransactionId?: string;
+ /**
+ * Always zero for refreshes
+ */
+ amountRaw: AmountString;
+ /**
+ * Fees, i.e. the effective, negative effect of the refresh
+ * on the balance.
+ *
+ * Only applicable for stand-alone refreshes, and zero for
+ * other refreshes where the transaction itself accounts for the
+ * refresh fee.
+ */
+ amountEffective: AmountString;
+ refreshInputAmount: AmountString;
+ refreshOutputAmount: AmountString;
+}
+```
+```typescript
+/**
+ * Reasons for why a coin is being refreshed.
+ */
+export declare enum RefreshReason {
+ Manual = "manual",
+ PayMerchant = "pay-merchant",
+ PayDeposit = "pay-deposit",
+ PayPeerPush = "pay-peer-push",
+ PayPeerPull = "pay-peer-pull",
+ Refund = "refund",
+ AbortPay = "abort-pay",
+ AbortDeposit = "abort-deposit",
+ Recoup = "recoup",
+ BackupRestored = "backup-restored",
+ Scheduled = "scheduled",
+}
+```
+```typescript
+/**
+ * Deposit transaction, which effectively sends
+ * money from this wallet somewhere else.
+ */
+export interface TransactionDeposit extends TransactionCommon {
+ type: TransactionType.Deposit;
+ depositGroupId: string;
+ /**
+ * Target for the deposit.
+ */
+ targetPaytoUri: string;
+ /**
+ * Raw amount that is being deposited
+ */
+ amountRaw: AmountString;
+ /**
+ * Effective amount that is being deposited
+ */
+ amountEffective: AmountString;
+ wireTransferDeadline: TalerProtocolTimestamp;
+ wireTransferProgress: number;
+ /**
+ * Did all the deposit requests succeed?
+ */
+ deposited: boolean;
+ trackingState: Array<{
+ wireTransferId: string;
+ timestampExecuted: TalerProtocolTimestamp;
+ amountRaw: AmountString;
+ wireFee: AmountString;
+ }>;
+}
+```
+```typescript
+/**
+ * Credit because we were paid for a P2P invoice we created.
+ */
+export interface TransactionPeerPullCredit extends TransactionCommon {
+ type: TransactionType.PeerPullCredit;
+ info: PeerInfoShort;
+ /**
+ * Exchange used.
+ */
+ exchangeBaseUrl: string;
+ /**
+ * Amount that got subtracted from the reserve balance.
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount that actually was (or will be) added to the wallet's balance.
+ */
+ amountEffective: AmountString;
+ /**
+ * URI to send to the other party.
+ */
+ talerUri: string;
+}
+```
+```typescript
+export interface PeerInfoShort {
+ expiration: TalerProtocolTimestamp | undefined;
+ summary: string | undefined;
+}
+```
+```typescript
+/**
+ * Debit because we paid someone's invoice.
+ */
+export interface TransactionPeerPullDebit extends TransactionCommon {
+ type: TransactionType.PeerPullDebit;
+ info: PeerInfoShort;
+ /**
+ * Exchange used.
+ */
+ exchangeBaseUrl: string;
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+}
+```
+```typescript
+/**
+ * We received money via a P2P payment.
+ */
+export interface TransactionPeerPushCredit extends TransactionCommon {
+ type: TransactionType.PeerPushCredit;
+ info: PeerInfoShort;
+ /**
+ * Exchange used.
+ */
+ exchangeBaseUrl: string;
+ /**
+ * Amount that got subtracted from the reserve balance.
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount that actually was (or will be) added to the wallet's balance.
+ */
+ amountEffective: AmountString;
+}
+```
+```typescript
+/**
+ * We sent money via a P2P payment.
+ */
+export interface TransactionPeerPushDebit extends TransactionCommon {
+ type: TransactionType.PeerPushDebit;
+ info: PeerInfoShort;
+ /**
+ * Exchange used.
+ */
+ exchangeBaseUrl: string;
+ /**
+ * Amount that got subtracted from the reserve balance.
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount that actually was (or will be) added to the wallet's balance.
+ */
+ amountEffective: AmountString;
+ /**
+ * URI to accept the payment.
+ */
+ talerUri: string;
+}
+```
+```typescript
+export interface AbortTransactionRequest {
+ transactionId: string;
+ /**
+ * Move the payment immediately into an aborted state.
+ * The UI should warn the user that this might lead
+ * to money being lost.
+ *
+ * Defaults to false.
+ */
+ forceImmediateAbort?: boolean;
+}
+```
+```typescript
+export interface ExchangeListItem {
+ exchangeBaseUrl: string;
+ currency: string | undefined;
+ paytoUris: string[];
+ tosStatus: ExchangeTosStatus;
+ exchangeStatus: ExchangeEntryStatus;
+ ageRestrictionOptions: number[];
+ /**
+ * Permanently added to the wallet, as opposed to just
+ * temporarily queried.
+ */
+ permanent: boolean;
+ /**
+ * Information about the last error that occurred when trying
+ * to update the exchange info.
+ */
+ lastUpdateErrorInfo?: OperationErrorInfo;
+}
+```
+```typescript
+export declare enum ExchangeTosStatus {
+ New = "new",
+ Accepted = "accepted",
+ Changed = "changed",
+ NotFound = "not-found",
+ Unknown = "unknown",
+}
+```
+```typescript
+export declare enum ExchangeEntryStatus {
+ Unknown = "unknown",
+ Outdated = "outdated",
+ Ok = "ok",
+}
+```
+```typescript
+export interface OperationErrorInfo {
+ error: TalerErrorDetail;
+}
+```
+```typescript
+export interface ForcedDenomSel {
+ denoms: {
+ value: AmountString;
+ count: number;
+ }[];
+}
+```
+```typescript
+/**
+ * Result of a prepare pay operation.
+ */
+export type PreparePayResult =
+ | PreparePayResultInsufficientBalance
+ | PreparePayResultAlreadyConfirmed
+ | PreparePayResultPaymentPossible;
+```
+```typescript
+export interface PreparePayResultInsufficientBalance {
+ status: PreparePayResultType.InsufficientBalance;
+ proposalId: string;
+ contractTerms: MerchantContractTerms;
+ amountRaw: string;
+ noncePriv: string;
+ talerUri: string;
+ balanceDetails: PayMerchantInsufficientBalanceDetails;
+}
+```
+```typescript
+/**
+ * Contract terms from a merchant.
+ * FIXME: Add type field!
+ */
+export interface MerchantContractTerms {
+ /**
+ * Hash of the merchant's wire details.
+ */
+ h_wire: string;
+ /**
+ * Hash of the merchant's wire details.
+ */
+ auto_refund?: TalerProtocolDuration;
+ /**
+ * Wire method the merchant wants to use.
+ */
+ wire_method: string;
+ /**
+ * Human-readable short summary of the contract.
+ */
+ summary: string;
+ summary_i18n?: InternationalizedString;
+ /**
+ * Nonce used to ensure freshness.
+ */
+ nonce: string;
+ /**
+ * Total amount payable.
+ */
+ amount: string;
+ /**
+ * Auditors accepted by the merchant.
+ */
+ auditors: AuditorHandle[];
+ /**
+ * Deadline to pay for the contract.
+ */
+ pay_deadline: TalerProtocolTimestamp;
+ /**
+ * Maximum deposit fee covered by the merchant.
+ */
+ max_fee: string;
+ /**
+ * Information about the merchant.
+ */
+ merchant: MerchantInfo;
+ /**
+ * Public key of the merchant.
+ */
+ merchant_pub: string;
+ /**
+ * Time indicating when the order should be delivered.
+ * May be overwritten by individual products.
+ */
+ delivery_date?: TalerProtocolTimestamp;
+ /**
+ * Delivery location for (all!) products.
+ */
+ delivery_location?: Location;
+ /**
+ * List of accepted exchanges.
+ */
+ exchanges: ExchangeHandle[];
+ /**
+ * Products that are sold in this contract.
+ */
+ products?: Product[];
+ /**
+ * Deadline for refunds.
+ */
+ refund_deadline: TalerProtocolTimestamp;
+ /**
+ * Deadline for the wire transfer.
+ */
+ wire_transfer_deadline: TalerProtocolTimestamp;
+ /**
+ * Time when the contract was generated by the merchant.
+ */
+ timestamp: TalerProtocolTimestamp;
+ /**
+ * Order id to uniquely identify the purchase within
+ * one merchant instance.
+ */
+ order_id: string;
+ /**
+ * Base URL of the merchant's backend.
+ */
+ merchant_base_url: string;
+ /**
+ * Fulfillment URL to view the product or
+ * delivery status.
+ */
+ fulfillment_url?: string;
+ /**
+ * URL meant to share the shopping cart.
+ */
+ public_reorder_url?: string;
+ /**
+ * Plain text fulfillment message in the merchant's default language.
+ */
+ fulfillment_message?: string;
+ /**
+ * Internationalized fulfillment messages.
+ */
+ fulfillment_message_i18n?: InternationalizedString;
+ /**
+ * Share of the wire fee that must be settled with one payment.
+ */
+ wire_fee_amortization?: number;
+ /**
+ * Maximum wire fee that the merchant agrees to pay for.
+ */
+ max_wire_fee?: string;
+ minimum_age?: number;
+ /**
+ * Extra data, interpreted by the mechant only.
+ */
+ extra?: any;
+}
+```
+```typescript
+export interface AuditorHandle {
+ /**
+ * Official name of the auditor.
+ */
+ name: string;
+ /**
+ * Master public signing key of the auditor.
+ */
+ auditor_pub: string;
+ /**
+ * Base URL of the auditor.
+ */
+ url: string;
+}
+```
+```typescript
+/**
+ * Information about an exchange as stored inside a
+ * merchant's contract terms.
+ */
+export interface ExchangeHandle {
+ /**
+ * Master public signing key of the exchange.
+ */
+ master_pub: string;
+ /**
+ * Base URL of the exchange.
+ */
+ url: string;
+}
+```
+```typescript
+/**
+ * Detailed reason for why the wallet's balance is insufficient.
+ */
+export interface PayMerchantInsufficientBalanceDetails {
+ /**
+ * Amount requested by the merchant.
+ */
+ amountRequested: AmountString;
+ /**
+ * Balance of type "available" (see balance.ts for definition).
+ */
+ balanceAvailable: AmountString;
+ /**
+ * Balance of type "material" (see balance.ts for definition).
+ */
+ balanceMaterial: AmountString;
+ /**
+ * Balance of type "age-acceptable" (see balance.ts for definition).
+ */
+ balanceAgeAcceptable: AmountString;
+ /**
+ * Balance of type "merchant-acceptable" (see balance.ts for definition).
+ */
+ balanceMerchantAcceptable: AmountString;
+ /**
+ * Balance of type "merchant-depositable" (see balance.ts for definition).
+ */
+ balanceMerchantDepositable: AmountString;
+ /**
+ * If the payment would succeed without fees
+ * (i.e. balanceMerchantDepositable >= amountRequested),
+ * this field contains an estimate of the amount that would additionally
+ * be required to cover the fees.
+ *
+ * It is not possible to give an exact value here, since it depends
+ * on the coin selection for the amount that would be additionally withdrawn.
+ */
+ feeGapEstimate: AmountString;
+}
+```
+```typescript
+export interface PreparePayResultAlreadyConfirmed {
+ status: PreparePayResultType.AlreadyConfirmed;
+ contractTerms: MerchantContractTerms;
+ paid: boolean;
+ amountRaw: string;
+ amountEffective: string;
+ contractTermsHash: string;
+ proposalId: string;
+ talerUri?: string;
+}
+```
+```typescript
+/**
+ * Payment is possible.
+ */
+export interface PreparePayResultPaymentPossible {
+ status: PreparePayResultType.PaymentPossible;
+ proposalId: string;
+ contractTerms: MerchantContractTerms;
+ contractTermsHash: string;
+ amountRaw: string;
+ amountEffective: string;
+ noncePriv: string;
+ talerUri: string;
+}
+```
+```typescript
+/**
+ * Forced coin selection for deposits/payments.
+ */
+export interface ForcedCoinSel {
+ coins: {
+ value: AmountString;
+ contribution: AmountString;
+ }[];
+}
+```
+```typescript
+export interface ApplyRefundResponse {
+ contractTermsHash: string;
+ transactionId: string;
+ proposalId: string;
+ amountEffectivePaid: AmountString;
+ amountRefundGranted: AmountString;
+ amountRefundGone: AmountString;
+ pendingAtExchange: boolean;
+ info: OrderShortInfo;
+}
+```
+```typescript
+export interface AddExchangeRequest {
+ exchangeBaseUrl: string;
+ forceUpdate?: boolean;
+}
+```
+```typescript
+export interface BackupRecovery {
+ walletRootPriv: string;
+ providers: {
+ name: string;
+ url: string;
+ }[];
+}
+```
+```typescript
+/**
+ * Contract terms between two wallets (as opposed to a merchant and wallet).
+ */
+export interface PeerContractTerms {
+ amount: AmountString;
+ summary: string;
+ purse_expiration: TalerProtocolTimestamp;
+}
+```
+```typescript
+export interface IntegrationTestArgs {
+ exchangeBaseUrl: string;
+ bankAccessApiBaseUrl: string;
+ merchantBaseUrl: string;
+ merchantAuthToken?: string;
+ amountToWithdraw: string;
+ amountToSpend: string;
+}
+```
diff --git a/extract-tsdefs/myout.md b/extract-tsdefs/myout.md
new file mode 100644
index 00000000..abecccf0
--- /dev/null
+++ b/extract-tsdefs/myout.md
@@ -0,0 +1,2517 @@
+# Wallet API Documentation
+```{note}
+This file is auto-generated from [wallet-core](https://git.taler.net/wallet-core.git/tree/packages/taler-wallet-core/src/wallet-api-types.ts)
+```
+## Overview
+### Initialization
+* [InitWalletOp](#initwalletop)
+### Basic Wallet Information
+* [GetBalancesOp](#getbalancesop)
+### Managing Transactions
+* [GetTransactionsOp](#gettransactionsop)
+* [DeleteTransactionOp](#deletetransactionop)
+* [RetryTransactionOp](#retrytransactionop)
+### Withdrawals
+* [GetWithdrawalDetailsForAmountOp](#getwithdrawaldetailsforamountop)
+* [GetWithdrawalDetailsForUriOp](#getwithdrawaldetailsforuriop)
+* [AcceptBankIntegratedWithdrawalOp](#acceptbankintegratedwithdrawalop)
+* [AcceptManualWithdrawalOp](#acceptmanualwithdrawalop)
+### Merchant Payments
+* [PreparePayForUriOp](#preparepayforuriop)
+* [ConfirmPayOp](#confirmpayop)
+* [AbortPayWithRefundOp](#abortpaywithrefundop)
+* [ApplyRefundOp](#applyrefundop)
+### Tipping
+* [PrepareTipOp](#preparetipop)
+* [AcceptTipOp](#accepttipop)
+### Exchange Management
+* [ListExchangesOp](#listexchangesop)
+* [AddExchangeOp](#addexchangeop)
+* [SetExchangeTosAcceptedOp](#setexchangetosacceptedop)
+* [GetExchangeTosOp](#getexchangetosop)
+* [ListCurrenciesOp](#listcurrenciesop)
+### Deposits
+* [CreateDepositGroupOp](#createdepositgroupop)
+* [TrackDepositGroupOp](#trackdepositgroupop)
+### Backups
+* [ExportBackupRecoveryOp](#exportbackuprecoveryop)
+* [ImportBackupRecoveryOp](#importbackuprecoveryop)
+* [RunBackupCycleOp](#runbackupcycleop)
+* [AddBackupProviderOp](#addbackupproviderop)
+* [GetBackupInfoOp](#getbackupinfoop)
+* [SetWalletDeviceIdOp](#setwalletdeviceidop)
+* [ExportBackupPlainOp](#exportbackupplainop)
+### Peer Payments
+* [InitiatePeerPushPaymentOp](#initiatepeerpushpaymentop)
+* [CheckPeerPushPaymentOp](#checkpeerpushpaymentop)
+* [AcceptPeerPushPaymentOp](#acceptpeerpushpaymentop)
+* [InitiatePeerPullPaymentOp](#initiatepeerpullpaymentop)
+* [CheckPeerPullPaymentOp](#checkpeerpullpaymentop)
+* [AcceptPeerPullPaymentOp](#acceptpeerpullpaymentop)
+### Database Management
+* [ExportDbOp](#exportdbop)
+* [ClearDbOp](#cleardbop)
+* [RecycleOp](#recycleop)
+### Testing and Debugging
+* [RunIntegrationTestOp](#runintegrationtestop)
+* [WithdrawTestBalanceOp](#withdrawtestbalanceop)
+* [WithdrawTestkudosOp](#withdrawtestkudosop)
+* [TestPayOp](#testpayop)
+* [WithdrawFakebankOp](#withdrawfakebankop)
+* [GetPendingTasksOp](#getpendingtasksop)
+* [DumpCoinsOp](#dumpcoinsop)
+* [SetCoinSuspendedOp](#setcoinsuspendedop)
+* [ForceRefreshOp](#forcerefreshop)
+## Operation Reference
+(initwalletop)=
+### InitWalletOp
+```typescript
+// group: Initialization
+/**
+ * Initialize wallet-core.
+ *
+ * Must be the request before any other operations.
+ */
+export type InitWalletOp = {
+ op: WalletApiOperation.InitWallet;
+ request: {};
+ response: {};
+};
+
+```
+```typescript
+// Enum value:
+// WalletApiOperation.InitWallet = "initWallet"
+
+```
+
+(getbalancesop)=
+### GetBalancesOp
+```typescript
+// group: Basic Wallet Information
+/**
+ * Get current wallet balance.
+ */
+export type GetBalancesOp = {
+ request: {};
+ response: BalancesResponse;
+};
+
+```
+```typescript
+export interface BalancesResponse {
+ balances: Balance[];
+}
+
+```
+```typescript
+export interface Balance {
+ available: AmountString;
+ pendingIncoming: AmountString;
+ pendingOutgoing: AmountString;
+ hasPendingTransactions: boolean;
+ requiresUserInput: boolean;
+}
+
+```
+
+(gettransactionsop)=
+### GetTransactionsOp
+```typescript
+// group: Managing Transactions
+/**
+ * Get transactions.
+ */
+export type GetTransactionsOp = {
+ request: TransactionsRequest;
+ response: TransactionsResponse;
+};
+
+```
+```typescript
+export interface TransactionsRequest {
+ /**
+ * return only transactions in the given currency
+ */
+ currency?: string;
+ /**
+ * if present, results will be limited to transactions related to the given search string
+ */
+ search?: string;
+}
+
+```
+```typescript
+export interface TransactionsResponse {
+ transactions: Transaction[];
+}
+
+```
+```typescript
+export declare type Transaction =
+ | TransactionWithdrawal
+ | TransactionPayment
+ | TransactionRefund
+ | TransactionTip
+ | TransactionRefresh
+ | TransactionDeposit
+ | TransactionPeerPullCredit
+ | TransactionPeerPullDebit
+ | TransactionPeerPushCredit
+ | TransactionPeerPushDebit;
+
+```
+```typescript
+export interface TransactionWithdrawal extends TransactionCommon {
+ type: TransactionType.Withdrawal;
+ /**
+ * Exchange of the withdrawal.
+ */
+ exchangeBaseUrl: string;
+ /**
+ * Amount that got subtracted from the reserve balance.
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount that actually was (or will be) added to the wallet's balance.
+ */
+ amountEffective: AmountString;
+ withdrawalDetails: WithdrawalDetails;
+}
+
+```
+```typescript
+// Enum value:
+// TransactionType.Withdrawal = "withdrawal"
+
+```
+```typescript
+export declare type WithdrawalDetails =
+ | WithdrawalDetailsForManualTransfer
+ | WithdrawalDetailsForTalerBankIntegrationApi;
+
+```
+```typescript
+interface WithdrawalDetailsForManualTransfer {
+ type: WithdrawalType.ManualTransfer;
+ /**
+ * Payto URIs that the exchange supports.
+ *
+ * Already contains the amount and message.
+ */
+ exchangePaytoUris: string[];
+ reservePub: string;
+}
+
+```
+```typescript
+// Enum value:
+// WithdrawalType.ManualTransfer = "manual-transfer"
+
+```
+```typescript
+interface WithdrawalDetailsForTalerBankIntegrationApi {
+ type: WithdrawalType.TalerBankIntegrationApi;
+ /**
+ * Set to true if the bank has confirmed the withdrawal, false if not.
+ * An unconfirmed withdrawal usually requires user-input and should be highlighted in the UI.
+ * See also bankConfirmationUrl below.
+ */
+ confirmed: boolean;
+ /**
+ * If the withdrawal is unconfirmed, this can include a URL for user
+ * initiated confirmation.
+ */
+ bankConfirmationUrl?: string;
+ reservePub: string;
+}
+
+```
+```typescript
+// Enum value:
+// WithdrawalType.TalerBankIntegrationApi = "taler-bank-integration-api"
+
+```
+```typescript
+export interface TransactionPayment extends TransactionCommon {
+ type: TransactionType.Payment;
+ /**
+ * Additional information about the payment.
+ */
+ info: OrderShortInfo;
+ /**
+ * Wallet-internal end-to-end identifier for the payment.
+ */
+ proposalId: string;
+ /**
+ * How far did the wallet get with processing the payment?
+ */
+ status: PaymentStatus;
+ /**
+ * Amount that must be paid for the contract
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount that was paid, including deposit, wire and refresh fees.
+ */
+ amountEffective: AmountString;
+ /**
+ * Amount that has been refunded by the merchant
+ */
+ totalRefundRaw: AmountString;
+ /**
+ * Amount will be added to the wallet's balance after fees and refreshing
+ */
+ totalRefundEffective: AmountString;
+ /**
+ * Amount pending to be picked up
+ */
+ refundPending: AmountString | undefined;
+ /**
+ * Reference to applied refunds
+ */
+ refunds: RefundInfoShort[];
+}
+
+```
+```typescript
+// Enum value:
+// TransactionType.Payment = "payment"
+
+```
+```typescript
+export declare enum PaymentStatus {
+ /**
+ * Explicitly aborted after timeout / failure
+ */
+ Aborted = "aborted",
+ /**
+ * Payment failed, wallet will auto-retry.
+ * User should be given the option to retry now / abort.
+ */
+ Failed = "failed",
+ /**
+ * Paid successfully
+ */
+ Paid = "paid",
+ /**
+ * User accepted, payment is processing.
+ */
+ Accepted = "accepted",
+}
+
+```
+```typescript
+export interface RefundInfoShort {
+ transactionId: string;
+ timestamp: TalerProtocolTimestamp;
+ amountEffective: AmountString;
+ amountRaw: AmountString;
+}
+
+```
+```typescript
+export interface TransactionRefund extends TransactionCommon {
+ type: TransactionType.Refund;
+ refundedTransactionId: string;
+ info: OrderShortInfo;
+ /**
+ * Amount pending to be picked up
+ */
+ refundPending: AmountString | undefined;
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+}
+
+```
+```typescript
+// Enum value:
+// TransactionType.Refund = "refund"
+
+```
+```typescript
+export interface TransactionTip extends TransactionCommon {
+ type: TransactionType.Tip;
+ amountRaw: AmountString;
+ /**
+ * More information about the merchant
+ */
+ amountEffective: AmountString;
+ merchantBaseUrl: string;
+}
+
+```
+```typescript
+// Enum value:
+// TransactionType.Tip = "tip"
+
+```
+```typescript
+export interface TransactionRefresh extends TransactionCommon {
+ type: TransactionType.Refresh;
+ exchangeBaseUrl: string;
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+}
+
+```
+```typescript
+/**
+ * Deposit transaction, which effectively sends
+ * money from this wallet somewhere else.
+ */
+export interface TransactionDeposit extends TransactionCommon {
+ type: TransactionType.Deposit;
+ depositGroupId: string;
+ /**
+ * Target for the deposit.
+ */
+ targetPaytoUri: string;
+ /**
+ * Raw amount that is being deposited
+ */
+ amountRaw: AmountString;
+ /**
+ * Effective amount that is being deposited
+ */
+ amountEffective: AmountString;
+}
+
+```
+```typescript
+/**
+ * Credit because we were paid for a P2P invoice we created.
+ */
+export interface TransactionPeerPullCredit extends TransactionCommon {
+ type: TransactionType.PeerPullCredit;
+ info: PeerInfoShort;
+ /**
+ * Exchange used.
+ */
+ exchangeBaseUrl: string;
+ /**
+ * Amount that got subtracted from the reserve balance.
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount that actually was (or will be) added to the wallet's balance.
+ */
+ amountEffective: AmountString;
+ /**
+ * URI to send to the other party.
+ */
+ talerUri: string;
+}
+
+```
+```typescript
+// Enum value:
+// TransactionType.PeerPullCredit = "peer-pull-credit"
+
+```
+```typescript
+export interface PeerInfoShort {
+ expiration: TalerProtocolTimestamp | undefined;
+ summary: string | undefined;
+}
+
+```
+```typescript
+/**
+ * Debit because we paid someone's invoice.
+ */
+export interface TransactionPeerPullDebit extends TransactionCommon {
+ type: TransactionType.PeerPullDebit;
+ info: PeerInfoShort;
+ /**
+ * Exchange used.
+ */
+ exchangeBaseUrl: string;
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+}
+
+```
+```typescript
+// Enum value:
+// TransactionType.PeerPullDebit = "peer-pull-debit"
+
+```
+```typescript
+/**
+ * We received money via a P2P payment.
+ */
+export interface TransactionPeerPushCredit extends TransactionCommon {
+ type: TransactionType.PeerPushCredit;
+ info: PeerInfoShort;
+ /**
+ * Exchange used.
+ */
+ exchangeBaseUrl: string;
+ /**
+ * Amount that got subtracted from the reserve balance.
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount that actually was (or will be) added to the wallet's balance.
+ */
+ amountEffective: AmountString;
+}
+
+```
+```typescript
+// Enum value:
+// TransactionType.PeerPushCredit = "peer-push-credit"
+
+```
+```typescript
+/**
+ * We sent money via a P2P payment.
+ */
+export interface TransactionPeerPushDebit extends TransactionCommon {
+ type: TransactionType.PeerPushDebit;
+ info: PeerInfoShort;
+ /**
+ * Exchange used.
+ */
+ exchangeBaseUrl: string;
+ /**
+ * Amount that got subtracted from the reserve balance.
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount that actually was (or will be) added to the wallet's balance.
+ */
+ amountEffective: AmountString;
+ /**
+ * URI to accept the payment.
+ */
+ talerUri: string;
+}
+
+```
+```typescript
+// Enum value:
+// TransactionType.PeerPushDebit = "peer-push-debit"
+
+```
+
+(deletetransactionop)=
+### DeleteTransactionOp
+```typescript
+/**
+ * Delete a transaction locally in the wallet.
+ */
+export type DeleteTransactionOp = {
+ request: DeleteTransactionRequest;
+ response: {};
+};
+
+```
+```typescript
+export interface DeleteTransactionRequest {
+ transactionId: string;
+}
+
+```
+
+(retrytransactionop)=
+### RetryTransactionOp
+```typescript
+/**
+ * Immediately retry a transaction.
+ */
+export type RetryTransactionOp = {
+ request: RetryTransactionRequest;
+ response: {};
+};
+
+```
+```typescript
+export interface RetryTransactionRequest {
+ transactionId: string;
+}
+
+```
+
+(getwithdrawaldetailsforamountop)=
+### GetWithdrawalDetailsForAmountOp
+```typescript
+// group: Withdrawals
+/**
+ * Get details for withdrawing a particular amount (manual withdrawal).
+ */
+export type GetWithdrawalDetailsForAmountOp = {
+ request: GetWithdrawalDetailsForAmountRequest;
+ response: ManualWithdrawalDetails;
+};
+
+```
+```typescript
+export interface GetWithdrawalDetailsForAmountRequest {
+ exchangeBaseUrl: string;
+ amount: string;
+ restrictAge?: number;
+}
+
+```
+```typescript
+export interface ManualWithdrawalDetails {
+ /**
+ * Did the user accept the current version of the exchange's
+ * terms of service?
+ */
+ tosAccepted: boolean;
+ /**
+ * Amount that the user will transfer to the exchange.
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount that will be added to the user's wallet balance.
+ */
+ amountEffective: AmountString;
+ /**
+ * Ways to pay the exchange.
+ */
+ paytoUris: string[];
+}
+
+```
+
+(getwithdrawaldetailsforuriop)=
+### GetWithdrawalDetailsForUriOp
+```typescript
+/**
+ * Get details for withdrawing via a particular taler:// URI.
+ */
+export type GetWithdrawalDetailsForUriOp = {
+ request: GetWithdrawalDetailsForUriRequest;
+ response: WithdrawUriInfoResponse;
+};
+
+```
+```typescript
+export interface GetWithdrawalDetailsForUriRequest {
+ talerWithdrawUri: string;
+ restrictAge?: number;
+}
+
+```
+```typescript
+export interface WithdrawUriInfoResponse {
+ amount: AmountString;
+ defaultExchangeBaseUrl?: string;
+ possibleExchanges: ExchangeListItem[];
+}
+
+```
+
+(acceptbankintegratedwithdrawalop)=
+### AcceptBankIntegratedWithdrawalOp
+```typescript
+/**
+ * Accept a bank-integrated withdrawal.
+ */
+export type AcceptBankIntegratedWithdrawalOp = {
+ request: AcceptBankIntegratedWithdrawalRequest;
+ response: AcceptWithdrawalResponse;
+};
+
+```
+```typescript
+export interface AcceptBankIntegratedWithdrawalRequest {
+ talerWithdrawUri: string;
+ exchangeBaseUrl: string;
+ forcedDenomSel?: ForcedDenomSel;
+ restrictAge?: number;
+}
+
+```
+```typescript
+export interface AcceptWithdrawalResponse {
+ reservePub: string;
+ confirmTransferUrl?: string;
+ transactionId: string;
+}
+
+```
+
+(acceptmanualwithdrawalop)=
+### AcceptManualWithdrawalOp
+```typescript
+/**
+ * Create a manual withdrawal.
+ */
+export type AcceptManualWithdrawalOp = {
+ request: AcceptManualWithdrawalRequest;
+ response: AcceptManualWithdrawalResult;
+};
+
+```
+```typescript
+export interface AcceptManualWithdrawalRequest {
+ exchangeBaseUrl: string;
+ amount: string;
+ restrictAge?: number;
+}
+
+```
+```typescript
+export interface AcceptManualWithdrawalResult {
+ /**
+ * Payto URIs that can be used to fund the withdrawal.
+ */
+ exchangePaytoUris: string[];
+ /**
+ * Public key of the newly created reserve.
+ */
+ reservePub: string;
+ transactionId: string;
+}
+
+```
+
+(preparepayforuriop)=
+### PreparePayForUriOp
+```typescript
+// group: Merchant Payments
+/**
+ * Prepare to make a payment
+ */
+export type PreparePayForUriOp = {
+ op: WalletApiOperation.PreparePayForUri;
+ request: PreparePayRequest;
+ response: PreparePayResult;
+};
+
+```
+```typescript
+// Enum value:
+// WalletApiOperation.PreparePayForUri = "preparePayForUri"
+
+```
+```typescript
+export interface PreparePayRequest {
+ talerPayUri: string;
+}
+
+```
+```typescript
+/**
+ * Result of a prepare pay operation.
+ */
+export declare type PreparePayResult =
+ | PreparePayResultInsufficientBalance
+ | PreparePayResultAlreadyConfirmed
+ | PreparePayResultPaymentPossible;
+
+```
+```typescript
+export interface PreparePayResultInsufficientBalance {
+ status: PreparePayResultType.InsufficientBalance;
+ proposalId: string;
+ contractTerms: ContractTerms;
+ amountRaw: string;
+ noncePriv: string;
+}
+
+```
+```typescript
+export interface PreparePayResultAlreadyConfirmed {
+ status: PreparePayResultType.AlreadyConfirmed;
+ contractTerms: ContractTerms;
+ paid: boolean;
+ amountRaw: string;
+ amountEffective: string;
+ contractTermsHash: string;
+ proposalId: string;
+}
+
+```
+```typescript
+// Enum value:
+// PreparePayResultType.AlreadyConfirmed = "already-confirmed"
+
+```
+```typescript
+/**
+ * Payment is possible.
+ */
+export interface PreparePayResultPaymentPossible {
+ status: PreparePayResultType.PaymentPossible;
+ proposalId: string;
+ contractTerms: ContractTerms;
+ contractTermsHash: string;
+ amountRaw: string;
+ amountEffective: string;
+ noncePriv: string;
+}
+
+```
+```typescript
+// Enum value:
+// PreparePayResultType.PaymentPossible = "payment-possible"
+
+```
+
+(confirmpayop)=
+### ConfirmPayOp
+```typescript
+/**
+ * Confirm a payment that was previously prepared with
+ * {@link PreparePayForUriOp}
+ */
+export type ConfirmPayOp = {
+ op: WalletApiOperation.ConfirmPay;
+ request: ConfirmPayRequest;
+ response: ConfirmPayResult;
+};
+
+```
+```typescript
+// Enum value:
+// WalletApiOperation.ConfirmPay = "confirmPay"
+
+```
+```typescript
+export interface ConfirmPayRequest {
+ proposalId: string;
+ sessionId?: string;
+ forcedCoinSel?: ForcedCoinSel;
+}
+
+```
+```typescript
+export declare type ConfirmPayResult =
+ | ConfirmPayResultDone
+ | ConfirmPayResultPending;
+
+```
+```typescript
+/**
+ * Result for confirmPay
+ */
+export interface ConfirmPayResultDone {
+ type: ConfirmPayResultType.Done;
+ contractTerms: ContractTerms;
+ transactionId: string;
+}
+
+```
+```typescript
+// Enum value:
+// ConfirmPayResultType.Done = "done"
+
+```
+```typescript
+export interface ConfirmPayResultPending {
+ type: ConfirmPayResultType.Pending;
+ transactionId: string;
+ lastError: TalerErrorDetail | undefined;
+}
+
+```
+
+(abortpaywithrefundop)=
+### AbortPayWithRefundOp
+```typescript
+/**
+ * Abort a pending payment with a refund.
+ */
+export type AbortPayWithRefundOp = {
+ request: AbortPayWithRefundRequest;
+ response: {};
+};
+
+```
+```typescript
+export interface AbortPayWithRefundRequest {
+ proposalId: string;
+}
+
+```
+
+(applyrefundop)=
+### ApplyRefundOp
+```typescript
+/**
+ * Check for a refund based on a taler://refund URI.
+ */
+export type ApplyRefundOp = {
+ request: ApplyRefundRequest;
+ response: ApplyRefundResponse;
+};
+
+```
+```typescript
+export interface ApplyRefundRequest {
+ talerRefundUri: string;
+}
+
+```
+```typescript
+export interface ApplyRefundResponse {
+ contractTermsHash: string;
+ transactionId: string;
+ proposalId: string;
+ amountEffectivePaid: AmountString;
+ amountRefundGranted: AmountString;
+ amountRefundGone: AmountString;
+ pendingAtExchange: boolean;
+ info: OrderShortInfo;
+}
+
+```
+
+(preparetipop)=
+### PrepareTipOp
+```typescript
+// group: Tipping
+/**
+ * Query and store information about a tip.
+ */
+export type PrepareTipOp = {
+ request: PrepareTipRequest;
+ response: PrepareTipResult;
+};
+
+```
+```typescript
+export interface PrepareTipRequest {
+ talerTipUri: string;
+}
+
+```
+```typescript
+export interface PrepareTipResult {
+ /**
+ * Unique ID for the tip assigned by the wallet.
+ * Typically different from the merchant-generated tip ID.
+ */
+ walletTipId: string;
+ /**
+ * Has the tip already been accepted?
+ */
+ accepted: boolean;
+ /**
+ * Amount that the merchant gave.
+ */
+ tipAmountRaw: AmountString;
+ /**
+ * Amount that arrived at the wallet.
+ * Might be lower than the raw amount due to fees.
+ */
+ tipAmountEffective: AmountString;
+ /**
+ * Base URL of the merchant backend giving then tip.
+ */
+ merchantBaseUrl: string;
+ /**
+ * Base URL of the exchange that is used to withdraw the tip.
+ * Determined by the merchant, the wallet/user has no choice here.
+ */
+ exchangeBaseUrl: string;
+ /**
+ * Time when the tip will expire. After it expired, it can't be picked
+ * up anymore.
+ */
+ expirationTimestamp: TalerProtocolTimestamp;
+}
+
+```
+
+(accepttipop)=
+### AcceptTipOp
+```typescript
+/**
+ * Accept a tip.
+ */
+export type AcceptTipOp = {
+ request: AcceptTipRequest;
+ response: {};
+};
+
+```
+```typescript
+export interface AcceptTipRequest {
+ walletTipId: string;
+}
+
+```
+
+(listexchangesop)=
+### ListExchangesOp
+```typescript
+// group: Exchange Management
+/**
+ * List exchanges known to the wallet.
+ */
+export type ListExchangesOp = {
+ request: {};
+ response: ExchangesListResponse;
+};
+
+```
+```typescript
+export interface ExchangesListResponse {
+ exchanges: ExchangeListItem[];
+}
+
+```
+
+(addexchangeop)=
+### AddExchangeOp
+```typescript
+/**
+ * Add / force-update an exchange.
+ */
+export type AddExchangeOp = {
+ request: AddExchangeRequest;
+ response: {};
+};
+
+```
+```typescript
+export interface AddExchangeRequest {
+ exchangeBaseUrl: string;
+ forceUpdate?: boolean;
+}
+
+```
+
+(setexchangetosacceptedop)=
+### SetExchangeTosAcceptedOp
+```typescript
+/**
+ * Accept a particular version of the exchange terms of service.
+ */
+export type SetExchangeTosAcceptedOp = {
+ request: AcceptExchangeTosRequest;
+ response: {};
+};
+
+```
+```typescript
+export interface AcceptExchangeTosRequest {
+ exchangeBaseUrl: string;
+ etag: string | undefined;
+}
+
+```
+
+(getexchangetosop)=
+### GetExchangeTosOp
+```typescript
+/**
+ * Get the current terms of a service of an exchange.
+ */
+export type GetExchangeTosOp = {
+ request: GetExchangeTosRequest;
+ response: GetExchangeTosResult;
+};
+
+```
+```typescript
+export interface GetExchangeTosRequest {
+ exchangeBaseUrl: string;
+ acceptedFormat?: string[];
+}
+
+```
+```typescript
+export interface GetExchangeTosResult {
+ /**
+ * Markdown version of the current ToS.
+ */
+ content: string;
+ /**
+ * Version tag of the current ToS.
+ */
+ currentEtag: string;
+ /**
+ * Version tag of the last ToS that the user has accepted,
+ * if any.
+ */
+ acceptedEtag: string | undefined;
+ /**
+ * Accepted content type
+ */
+ contentType: string;
+}
+
+```
+
+(listcurrenciesop)=
+### ListCurrenciesOp
+```typescript
+/**
+ * List currencies known to the wallet.
+ */
+export type ListCurrenciesOp = {
+ request: {};
+ response: WalletCurrencyInfo;
+};
+
+```
+```typescript
+export interface WalletCurrencyInfo {
+ trustedAuditors: {
+ currency: string;
+ auditorPub: string;
+ auditorBaseUrl: string;
+ }[];
+ trustedExchanges: {
+ currency: string;
+ exchangeMasterPub: string;
+ exchangeBaseUrl: string;
+ }[];
+}
+
+```
+
+(createdepositgroupop)=
+### CreateDepositGroupOp
+```typescript
+// group: Deposits
+/**
+ * Create a new deposit group.
+ *
+ * Deposit groups are used to deposit multiple coins to a bank
+ * account, usually the wallet user's own bank account.
+ */
+export type CreateDepositGroupOp = {
+ request: CreateDepositGroupRequest;
+ response: CreateDepositGroupResponse;
+};
+
+```
+```typescript
+export interface CreateDepositGroupRequest {
+ depositPaytoUri: string;
+ amount: AmountString;
+}
+
+```
+```typescript
+export interface CreateDepositGroupResponse {
+ depositGroupId: string;
+ transactionId: string;
+}
+
+```
+
+(trackdepositgroupop)=
+### TrackDepositGroupOp
+```typescript
+/**
+ * Track the status of a deposit group by querying the exchange.
+ */
+export type TrackDepositGroupOp = {
+ request: TrackDepositGroupRequest;
+ response: TrackDepositGroupResponse;
+};
+
+```
+```typescript
+export interface TrackDepositGroupRequest {
+ depositGroupId: string;
+}
+
+```
+```typescript
+export interface TrackDepositGroupResponse {
+ responses: {
+ status: number;
+ body: any;
+ }[];
+}
+
+```
+
+(exportbackuprecoveryop)=
+### ExportBackupRecoveryOp
+```typescript
+// group: Backups
+/**
+ * Export the recovery information for the wallet.
+ */
+export type ExportBackupRecoveryOp = {
+ request: {};
+ response: BackupRecovery;
+};
+
+```
+
+(importbackuprecoveryop)=
+### ImportBackupRecoveryOp
+```typescript
+/**
+ * Import recovery information into the wallet.
+ */
+export type ImportBackupRecoveryOp = {
+ request: RecoveryLoadRequest;
+ response: {};
+};
+
+```
+```typescript
+/**
+ * Load recovery information into the wallet.
+ */
+export interface RecoveryLoadRequest {
+ recovery: BackupRecovery;
+ strategy?: RecoveryMergeStrategy;
+}
+
+```
+```typescript
+/**
+ * Strategy for loading recovery information.
+ */
+export declare enum RecoveryMergeStrategy {
+ /**
+ * Keep the local wallet root key, import and take over providers.
+ */
+ Ours = "ours",
+ /**
+ * Migrate to the wallet root key from the recovery information.
+ */
+ Theirs = "theirs",
+}
+
+```
+
+(runbackupcycleop)=
+### RunBackupCycleOp
+```typescript
+/**
+ * Manually make and upload a backup.
+ */
+export type RunBackupCycleOp = {
+ request: {};
+ response: {};
+};
+
+```
+
+(addbackupproviderop)=
+### AddBackupProviderOp
+```typescript
+/**
+ * Add a new backup provider.
+ */
+export type AddBackupProviderOp = {
+ request: AddBackupProviderRequest;
+ response: {};
+};
+
+```
+```typescript
+export interface AddBackupProviderRequest {
+ backupProviderBaseUrl: string;
+ name: string;
+ /**
+ * Activate the provider. Should only be done after
+ * the user has reviewed the provider.
+ */
+ activate?: boolean;
+}
+
+```
+
+(getbackupinfoop)=
+### GetBackupInfoOp
+```typescript
+/**
+ * Get some useful stats about the backup state.
+ */
+export type GetBackupInfoOp = {
+ request: {};
+ response: BackupInfo;
+};
+
+```
+```typescript
+export interface BackupInfo {
+ walletRootPub: string;
+ deviceId: string;
+ providers: ProviderInfo[];
+}
+
+```
+```typescript
+/**
+ * Information about one provider.
+ *
+ * We don't store the account key here,
+ * as that's derived from the wallet root key.
+ */
+export interface ProviderInfo {
+ active: boolean;
+ syncProviderBaseUrl: string;
+ name: string;
+ terms?: BackupProviderTerms;
+ /**
+ * Last communication issue with the provider.
+ */
+ lastError?: TalerErrorDetail;
+ lastSuccessfulBackupTimestamp?: TalerProtocolTimestamp;
+ lastAttemptedBackupTimestamp?: TalerProtocolTimestamp;
+ paymentProposalIds: string[];
+ backupProblem?: BackupProblem;
+ paymentStatus: ProviderPaymentStatus;
+}
+
+```
+```typescript
+export interface BackupProviderTerms {
+ supportedProtocolVersion: string;
+ annualFee: AmountString;
+ storageLimitInMegabytes: number;
+}
+
+```
+```typescript
+export type BackupProblem =
+ | BackupUnreadableProblem
+ | BackupConflictingDeviceProblem;
+
+```
+```typescript
+export interface BackupUnreadableProblem {
+ type: "backup-unreadable";
+}
+
+```
+```typescript
+export interface BackupConflictingDeviceProblem {
+ type: "backup-conflicting-device";
+ otherDeviceId: string;
+ myDeviceId: string;
+ backupTimestamp: AbsoluteTime;
+}
+
+```
+```typescript
+export type ProviderPaymentStatus =
+ | ProviderPaymentTermsChanged
+ | ProviderPaymentPaid
+ | ProviderPaymentInsufficientBalance
+ | ProviderPaymentUnpaid
+ | ProviderPaymentPending;
+
+```
+```typescript
+export interface ProviderPaymentTermsChanged {
+ type: ProviderPaymentType.TermsChanged;
+ paidUntil: AbsoluteTime;
+ oldTerms: BackupProviderTerms;
+ newTerms: BackupProviderTerms;
+}
+
+```
+```typescript
+// Enum value:
+// ProviderPaymentType.TermsChanged = "terms-changed"
+
+```
+```typescript
+export interface ProviderPaymentPaid {
+ type: ProviderPaymentType.Paid;
+ paidUntil: AbsoluteTime;
+}
+
+```
+```typescript
+// Enum value:
+// ProviderPaymentType.Paid = "paid"
+
+```
+```typescript
+export interface ProviderPaymentInsufficientBalance {
+ type: ProviderPaymentType.InsufficientBalance;
+}
+
+```
+```typescript
+export interface ProviderPaymentUnpaid {
+ type: ProviderPaymentType.Unpaid;
+}
+
+```
+```typescript
+// Enum value:
+// ProviderPaymentType.Unpaid = "unpaid"
+
+```
+```typescript
+export interface ProviderPaymentPending {
+ type: ProviderPaymentType.Pending;
+}
+
+```
+
+(setwalletdeviceidop)=
+### SetWalletDeviceIdOp
+```typescript
+/**
+ * Set the internal device ID of the wallet, used to
+ * identify whether a different/new wallet is accessing
+ * the backup of another wallet.
+ */
+export type SetWalletDeviceIdOp = {
+ request: SetWalletDeviceIdRequest;
+ response: {};
+};
+
+```
+```typescript
+export interface SetWalletDeviceIdRequest {
+ /**
+ * New wallet device ID to set.
+ */
+ walletDeviceId: string;
+}
+
+```
+
+(exportbackupplainop)=
+### ExportBackupPlainOp
+```typescript
+/**
+ * Export a backup JSON, mostly useful for testing.
+ */
+export type ExportBackupPlainOp = {
+ request: {};
+ response: WalletBackupContentV1;
+};
+
+```
+
+(initiatepeerpushpaymentop)=
+### InitiatePeerPushPaymentOp
+```typescript
+// group: Peer Payments
+/**
+ * Initiate an outgoing peer push payment.
+ */
+export type InitiatePeerPushPaymentOp = {
+ request: InitiatePeerPushPaymentRequest;
+ response: InitiatePeerPushPaymentResponse;
+};
+
+```
+```typescript
+export interface InitiatePeerPushPaymentRequest {
+ amount: AmountString;
+ partialContractTerms: any;
+}
+
+```
+```typescript
+export interface InitiatePeerPushPaymentResponse {
+ exchangeBaseUrl: string;
+ pursePub: string;
+ mergePriv: string;
+ contractPriv: string;
+ talerUri: string;
+ transactionId: string;
+}
+
+```
+
+(checkpeerpushpaymentop)=
+### CheckPeerPushPaymentOp
+```typescript
+/**
+ * Check an incoming peer push payment.
+ */
+export type CheckPeerPushPaymentOp = {
+ request: CheckPeerPushPaymentRequest;
+ response: CheckPeerPushPaymentResponse;
+};
+
+```
+```typescript
+export interface CheckPeerPushPaymentRequest {
+ talerUri: string;
+}
+
+```
+```typescript
+export interface CheckPeerPushPaymentResponse {
+ contractTerms: any;
+ amount: AmountString;
+ peerPushPaymentIncomingId: string;
+}
+
+```
+
+(acceptpeerpushpaymentop)=
+### AcceptPeerPushPaymentOp
+```typescript
+/**
+ * Accept an incoming peer push payment.
+ */
+export type AcceptPeerPushPaymentOp = {
+ request: AcceptPeerPushPaymentRequest;
+ response: {};
+};
+
+```
+```typescript
+export interface AcceptPeerPushPaymentRequest {
+ /**
+ * Transparent identifier of the incoming peer push payment.
+ */
+ peerPushPaymentIncomingId: string;
+}
+
+```
+
+(initiatepeerpullpaymentop)=
+### InitiatePeerPullPaymentOp
+```typescript
+/**
+ * Initiate an outgoing peer pull payment.
+ */
+export type InitiatePeerPullPaymentOp = {
+ request: InitiatePeerPullPaymentRequest;
+ response: InitiatePeerPullPaymentResponse;
+};
+
+```
+```typescript
+export interface InitiatePeerPullPaymentRequest {
+ /**
+ * FIXME: Make this optional?
+ */
+ exchangeBaseUrl: string;
+ amount: AmountString;
+ partialContractTerms: any;
+}
+
+```
+```typescript
+export interface InitiatePeerPullPaymentResponse {
+ /**
+ * Taler URI for the other party to make the payment
+ * that was requested.
+ */
+ talerUri: string;
+ transactionId: string;
+}
+
+```
+
+(checkpeerpullpaymentop)=
+### CheckPeerPullPaymentOp
+```typescript
+/**
+ * Prepare for an incoming peer pull payment.
+ */
+export type CheckPeerPullPaymentOp = {
+ request: CheckPeerPullPaymentRequest;
+ response: CheckPeerPullPaymentResponse;
+};
+
+```
+```typescript
+export interface CheckPeerPullPaymentRequest {
+ talerUri: string;
+}
+
+```
+```typescript
+export interface CheckPeerPullPaymentResponse {
+ contractTerms: any;
+ amount: AmountString;
+ peerPullPaymentIncomingId: string;
+}
+
+```
+
+(acceptpeerpullpaymentop)=
+### AcceptPeerPullPaymentOp
+```typescript
+/**
+ * Accept an incoming peer pull payment.
+ */
+export type AcceptPeerPullPaymentOp = {
+ request: AcceptPeerPullPaymentRequest;
+ response: {};
+};
+
+```
+```typescript
+export interface AcceptPeerPullPaymentRequest {
+ /**
+ * Transparent identifier of the incoming peer pull payment.
+ */
+ peerPullPaymentIncomingId: string;
+}
+
+```
+
+(exportdbop)=
+### ExportDbOp
+```typescript
+// group: Database Management
+/**
+ * Exoport the wallet database's contents to JSON.
+ */
+export type ExportDbOp = {
+ request: {};
+ response: any;
+};
+
+```
+
+(cleardbop)=
+### ClearDbOp
+```typescript
+/**
+ * Dangerously clear the whole wallet database.
+ */
+export type ClearDbOp = {
+ request: {};
+ response: {};
+};
+
+```
+
+(recycleop)=
+### RecycleOp
+```typescript
+/**
+ * Export a backup, clear the database and re-import it.
+ */
+export type RecycleOp = {
+ request: {};
+ response: {};
+};
+
+```
+
+(runintegrationtestop)=
+### RunIntegrationTestOp
+```typescript
+// group: Testing and Debugging
+/**
+ * Run a simple integration test on a test deployment
+ * of the exchange and merchant.
+ */
+export type RunIntegrationTestOp = {
+ request: IntegrationTestArgs;
+ response: {};
+};
+
+```
+```typescript
+export interface IntegrationTestArgs {
+ exchangeBaseUrl: string;
+ bankBaseUrl: string;
+ bankAccessApiBaseUrl?: string;
+ merchantBaseUrl: string;
+ merchantAuthToken?: string;
+ amountToWithdraw: string;
+ amountToSpend: string;
+}
+
+```
+
+(withdrawtestbalanceop)=
+### WithdrawTestBalanceOp
+```typescript
+/**
+ * Make withdrawal on a test deployment of the exchange
+ * and merchant.
+ */
+export type WithdrawTestBalanceOp = {
+ request: WithdrawTestBalanceRequest;
+ response: {};
+};
+
+```
+```typescript
+export interface WithdrawTestBalanceRequest {
+ amount: string;
+ bankBaseUrl: string;
+ /**
+ * Bank access API base URL. Defaults to the bankBaseUrl.
+ */
+ bankAccessApiBaseUrl?: string;
+ exchangeBaseUrl: string;
+ forcedDenomSel?: ForcedDenomSel;
+}
+
+```
+
+(withdrawtestkudosop)=
+### WithdrawTestkudosOp
+```typescript
+/**
+ * Make a withdrawal of testkudos on test.taler.net.
+ */
+export type WithdrawTestkudosOp = {
+ op: WalletApiOperation.WithdrawTestkudos;
+ request: {};
+ response: {};
+};
+
+```
+```typescript
+// Enum value:
+// WalletApiOperation.WithdrawTestkudos = "withdrawTestkudos"
+
+```
+
+(testpayop)=
+### TestPayOp
+```typescript
+/**
+ * Make a test payment using a test deployment of
+ * the exchange and merchant.
+ */
+export type TestPayOp = {
+ request: TestPayArgs;
+ response: TestPayResult;
+};
+
+```
+```typescript
+export interface TestPayArgs {
+ merchantBaseUrl: string;
+ merchantAuthToken?: string;
+ amount: string;
+ summary: string;
+ forcedCoinSel?: ForcedCoinSel;
+}
+
+```
+```typescript
+export interface TestPayResult {
+ payCoinSelection: PayCoinSelection;
+}
+
+```
+```typescript
+/**
+ * Result of selecting coins, contains the exchange, and selected
+ * coins with their denomination.
+ */
+export interface PayCoinSelection {
+ /**
+ * Amount requested by the merchant.
+ */
+ paymentAmount: AmountJson;
+ /**
+ * Public keys of the coins that were selected.
+ */
+ coinPubs: string[];
+ /**
+ * Amount that each coin contributes.
+ */
+ coinContributions: AmountJson[];
+ /**
+ * How much of the wire fees is the customer paying?
+ */
+ customerWireFees: AmountJson;
+ /**
+ * How much of the deposit fees is the customer paying?
+ */
+ customerDepositFees: AmountJson;
+}
+
+```
+```typescript
+/**
+ * Non-negative financial amount. Fractional values are expressed as multiples
+ * of 1e-8.
+ */
+export interface AmountJson {
+ /**
+ * Value, must be an integer.
+ */
+ readonly value: number;
+ /**
+ * Fraction, must be an integer. Represent 1/1e8 of a unit.
+ */
+ readonly fraction: number;
+ /**
+ * Currency of the amount.
+ */
+ readonly currency: string;
+}
+
+```
+
+(withdrawfakebankop)=
+### WithdrawFakebankOp
+```typescript
+/**
+ * Make a withdrawal from a fakebank, i.e.
+ * a bank where test users can be registered freely
+ * and testing APIs are available.
+ */
+export type WithdrawFakebankOp = {
+ op: WalletApiOperation.WithdrawFakebank;
+ request: WithdrawFakebankRequest;
+ response: {};
+};
+
+```
+```typescript
+// Enum value:
+// WalletApiOperation.WithdrawFakebank = "withdrawFakebank"
+
+```
+```typescript
+export interface WithdrawFakebankRequest {
+ amount: AmountString;
+ exchange: string;
+ bank: string;
+}
+
+```
+
+(getpendingtasksop)=
+### GetPendingTasksOp
+```typescript
+/**
+ * Get wallet-internal pending tasks.
+ */
+export type GetPendingTasksOp = {
+ request: {};
+ response: PendingTasksResponse;
+};
+
+```
+```typescript
+/**
+ * Response returned from the pending operations API.
+ */
+export interface PendingOperationsResponse {
+ /**
+ * List of pending operations.
+ */
+ pendingOperations: PendingTaskInfo[];
+}
+
+```
+```typescript
+/**
+ * Information about a pending operation.
+ */
+export type PendingTaskInfo = PendingTaskInfoCommon &
+ (
+ | PendingExchangeUpdateTask
+ | PendingExchangeCheckRefreshTask
+ | PendingPayTask
+ | PendingProposalDownloadTask
+ | PendingRefreshTask
+ | PendingRefundQueryTask
+ | PendingTipPickupTask
+ | PendingWithdrawTask
+ | PendingRecoupTask
+ | PendingDepositTask
+ | PendingBackupTask
+ );
+
+```
+```typescript
+/**
+ * Fields that are present in every pending operation.
+ */
+export interface PendingTaskInfoCommon {
+ /**
+ * Type of the pending operation.
+ */
+ type: PendingTaskType;
+ /**
+ * Unique identifier for the pending task.
+ */
+ id: string;
+ /**
+ * Set to true if the operation indicates that something is really in progress,
+ * as opposed to some regular scheduled operation that can be tried later.
+ */
+ givesLifeness: boolean;
+ /**
+ * Timestamp when the pending operation should be executed next.
+ */
+ timestampDue: AbsoluteTime;
+ /**
+ * Retry info. Currently used to stop the wallet after any operation
+ * exceeds a number of retries.
+ */
+ retryInfo?: RetryInfo;
+}
+
+```
+```typescript
+export enum PendingTaskType {
+ ExchangeUpdate = "exchange-update",
+ ExchangeCheckRefresh = "exchange-check-refresh",
+ Pay = "pay",
+ ProposalDownload = "proposal-download",
+ Refresh = "refresh",
+ Recoup = "recoup",
+ RefundQuery = "refund-query",
+ TipPickup = "tip-pickup",
+ Withdraw = "withdraw",
+ Deposit = "deposit",
+ Backup = "backup",
+}
+
+```
+```typescript
+export interface RetryInfo {
+ firstTry: AbsoluteTime;
+ nextRetry: AbsoluteTime;
+ retryCounter: number;
+}
+
+```
+```typescript
+export interface RetryPolicy {
+ readonly backoffDelta: Duration;
+ readonly backoffBase: number;
+ readonly maxTimeout: Duration;
+}
+
+```
+```typescript
+/**
+ * The wallet is currently updating information about an exchange.
+ */
+export interface PendingExchangeUpdateTask {
+ type: PendingTaskType.ExchangeUpdate;
+ exchangeBaseUrl: string;
+ lastError: TalerErrorDetail | undefined;
+}
+
+```
+```typescript
+// Enum value:
+// PendingTaskType.ExchangeUpdate = "exchange-update"
+
+```
+```typescript
+/**
+ * The wallet should check whether coins from this exchange
+ * need to be auto-refreshed.
+ */
+export interface PendingExchangeCheckRefreshTask {
+ type: PendingTaskType.ExchangeCheckRefresh;
+ exchangeBaseUrl: string;
+}
+
+```
+```typescript
+// Enum value:
+// PendingTaskType.ExchangeCheckRefresh = "exchange-check-refresh"
+
+```
+```typescript
+/**
+ * The wallet is signing coins and then sending them to
+ * the merchant.
+ */
+export interface PendingPayTask {
+ type: PendingTaskType.Pay;
+ proposalId: string;
+ isReplay: boolean;
+ retryInfo?: RetryInfo;
+ lastError: TalerErrorDetail | undefined;
+}
+
+```
+```typescript
+// Enum value:
+// PendingTaskType.Pay = "pay"
+
+```
+```typescript
+/**
+ * Status of downloading signed contract terms from a merchant.
+ */
+export interface PendingProposalDownloadTask {
+ type: PendingTaskType.ProposalDownload;
+ merchantBaseUrl: string;
+ proposalTimestamp: TalerProtocolTimestamp;
+ proposalId: string;
+ orderId: string;
+ lastError?: TalerErrorDetail;
+ retryInfo?: RetryInfo;
+}
+
+```
+```typescript
+// Enum value:
+// PendingTaskType.ProposalDownload = "proposal-download"
+
+```
+```typescript
+/**
+ * Status of an ongoing withdrawal operation.
+ */
+export interface PendingRefreshTask {
+ type: PendingTaskType.Refresh;
+ lastError?: TalerErrorDetail;
+ refreshGroupId: string;
+ finishedPerCoin: boolean[];
+ retryInfo?: RetryInfo;
+}
+
+```
+```typescript
+/**
+ * The wallet is querying the merchant about whether any refund
+ * permissions are available for a purchase.
+ */
+export interface PendingRefundQueryTask {
+ type: PendingTaskType.RefundQuery;
+ proposalId: string;
+ retryInfo?: RetryInfo;
+ lastError: TalerErrorDetail | undefined;
+}
+
+```
+```typescript
+// Enum value:
+// PendingTaskType.RefundQuery = "refund-query"
+
+```
+```typescript
+/**
+ * The wallet is picking up a tip that the user has accepted.
+ */
+export interface PendingTipPickupTask {
+ type: PendingTaskType.TipPickup;
+ tipId: string;
+ merchantBaseUrl: string;
+ merchantTipId: string;
+}
+
+```
+```typescript
+// Enum value:
+// PendingTaskType.TipPickup = "tip-pickup"
+
+```
+```typescript
+/**
+ * Status of an ongoing withdrawal operation.
+ */
+export interface PendingWithdrawTask {
+ type: PendingTaskType.Withdraw;
+ lastError: TalerErrorDetail | undefined;
+ retryInfo?: RetryInfo;
+ withdrawalGroupId: string;
+}
+
+```
+```typescript
+// Enum value:
+// PendingTaskType.Withdraw = "withdraw"
+
+```
+```typescript
+export interface PendingRecoupTask {
+ type: PendingTaskType.Recoup;
+ recoupGroupId: string;
+ retryInfo?: RetryInfo;
+ lastError: TalerErrorDetail | undefined;
+}
+
+```
+```typescript
+// Enum value:
+// PendingTaskType.Recoup = "recoup"
+
+```
+```typescript
+/**
+ * Status of an ongoing deposit operation.
+ */
+export interface PendingDepositTask {
+ type: PendingTaskType.Deposit;
+ lastError: TalerErrorDetail | undefined;
+ retryInfo: RetryInfo | undefined;
+ depositGroupId: string;
+}
+
+```
+```typescript
+export interface PendingBackupTask {
+ type: PendingTaskType.Backup;
+ backupProviderBaseUrl: string;
+ lastError: TalerErrorDetail | undefined;
+}
+
+```
+```typescript
+// Enum value:
+// PendingTaskType.Backup = "backup"
+
+```
+
+(dumpcoinsop)=
+### DumpCoinsOp
+```typescript
+/**
+ * Dump all coins of the wallet in a simple JSON format.
+ */
+export type DumpCoinsOp = {
+ request: {};
+ response: CoinDumpJson;
+};
+
+```
+```typescript
+/**
+ * Easy to process format for the public data of coins
+ * managed by the wallet.
+ */
+export interface CoinDumpJson {
+ coins: Array<{
+ /**
+ * The coin's denomination's public key.
+ */
+ denom_pub: DenominationPubKey;
+ /**
+ * Hash of denom_pub.
+ */
+ denom_pub_hash: string;
+ /**
+ * Value of the denomination (without any fees).
+ */
+ denom_value: string;
+ /**
+ * Public key of the coin.
+ */
+ coin_pub: string;
+ /**
+ * Base URL of the exchange for the coin.
+ */
+ exchange_base_url: string;
+ /**
+ * Remaining value on the coin, to the knowledge of
+ * the wallet.
+ */
+ remaining_value: string;
+ /**
+ * Public key of the parent coin.
+ * Only present if this coin was obtained via refreshing.
+ */
+ refresh_parent_coin_pub: string | undefined;
+ /**
+ * Public key of the reserve for this coin.
+ * Only present if this coin was obtained via refreshing.
+ */
+ withdrawal_reserve_pub: string | undefined;
+ /**
+ * Is the coin suspended?
+ * Suspended coins are not considered for payments.
+ */
+ coin_suspended: boolean;
+ /**
+ * Information about the age restriction
+ */
+ ageCommitmentProof: AgeCommitmentProof | undefined;
+ }>;
+}
+
+```
+```typescript
+interface Array<T> extends RelativeIndexable<T> {}
+
+```
+
+(setcoinsuspendedop)=
+### SetCoinSuspendedOp
+```typescript
+/**
+ * Set a coin as (un-)suspended.
+ * Suspended coins won't be used for payments.
+ */
+export type SetCoinSuspendedOp = {
+ request: SetCoinSuspendedRequest;
+ response: {};
+};
+
+```
+```typescript
+export interface SetCoinSuspendedRequest {
+ coinPub: string;
+ suspended: boolean;
+}
+
+```
+
+(forcerefreshop)=
+### ForceRefreshOp
+```typescript
+/**
+ * Force a refresh on coins where it would not
+ * be necessary.
+ */
+export type ForceRefreshOp = {
+ request: ForceRefreshRequest;
+ response: {};
+};
+
+```
+```typescript
+export interface ForceRefreshRequest {
+ coinPubList: string[];
+}
+
+```
+
+## Common Declarations
+```typescript
+export interface OrderShortInfo {
+ /**
+ * Order ID, uniquely identifies the order within a merchant instance
+ */
+ orderId: string;
+ /**
+ * Hash of the contract terms.
+ */
+ contractTermsHash: string;
+ /**
+ * More information about the merchant
+ */
+ merchant: MerchantInfo;
+ /**
+ * Summary of the order, given by the merchant
+ */
+ summary: string;
+ /**
+ * Map from IETF BCP 47 language tags to localized summaries
+ */
+ summary_i18n?: InternationalizedString;
+ /**
+ * List of products that are part of the order
+ */
+ products: Product[] | undefined;
+ /**
+ * Time indicating when the order should be delivered.
+ * May be overwritten by individual products.
+ */
+ delivery_date?: TalerProtocolTimestamp;
+ /**
+ * Delivery location for (all!) products.
+ */
+ delivery_location?: Location;
+ /**
+ * URL of the fulfillment, given by the merchant
+ */
+ fulfillmentUrl?: string;
+ /**
+ * Plain text message that should be shown to the user
+ * when the payment is complete.
+ */
+ fulfillmentMessage?: string;
+ /**
+ * Translations of fulfillmentMessage.
+ */
+ fulfillmentMessage_i18n?: InternationalizedString;
+}
+```
+```typescript
+export interface MerchantInfo {
+ name: string;
+ jurisdiction?: Location;
+ address?: Location;
+ logo?: string;
+ website?: string;
+ email?: string;
+}
+```
+```typescript
+export interface Location {
+ country?: string;
+ country_subdivision?: string;
+ district?: string;
+ town?: string;
+ town_location?: string;
+ post_code?: string;
+ street?: string;
+ building_name?: string;
+ building_number?: string;
+ address_lines?: string[];
+}
+```
+```typescript
+export interface InternationalizedString {
+ [lang_tag: string]: string;
+}
+```
+```typescript
+export interface Product {
+ product_id?: string;
+ description: string;
+ description_i18n?: {
+ [lang_tag: string]: string;
+ };
+ quantity?: number;
+ unit?: string;
+ price?: AmountString;
+ image?: string;
+ taxes?: Tax[];
+ delivery_date?: TalerProtocolTimestamp;
+}
+```
+```typescript
+export interface Tax {
+ name: string;
+ tax: AmountString;
+}
+```
+```typescript
+export interface TalerProtocolTimestamp {
+ readonly t_s: number | "never";
+}
+```
+```typescript
+// Enum value:
+// PendingTaskType.Refresh = "refresh"
+```
+```typescript
+// Enum value:
+// PendingTaskType.Deposit = "deposit"
+```
+```typescript
+export interface ExchangeListItem {
+ exchangeBaseUrl: string;
+ currency: string;
+ paytoUris: string[];
+ tos: ExchangeTos;
+}
+```
+```typescript
+export interface ExchangeTos {
+ acceptedVersion?: string;
+ currentVersion?: string;
+ contentType?: string;
+ content?: string;
+}
+```
+```typescript
+export interface ForcedDenomSel {
+ denoms: {
+ value: AmountString;
+ count: number;
+ }[];
+}
+```
+```typescript
+// Enum value:
+// ProviderPaymentType.InsufficientBalance = "insufficient-balance"
+```
+```typescript
+/**
+ * Contract terms from a merchant.
+ */
+export interface ContractTerms {
+ /**
+ * Hash of the merchant's wire details.
+ */
+ h_wire: string;
+ /**
+ * Hash of the merchant's wire details.
+ */
+ auto_refund?: TalerProtocolDuration;
+ /**
+ * Wire method the merchant wants to use.
+ */
+ wire_method: string;
+ /**
+ * Human-readable short summary of the contract.
+ */
+ summary: string;
+ summary_i18n?: InternationalizedString;
+ /**
+ * Nonce used to ensure freshness.
+ */
+ nonce: string;
+ /**
+ * Total amount payable.
+ */
+ amount: string;
+ /**
+ * Auditors accepted by the merchant.
+ */
+ auditors: AuditorHandle[];
+ /**
+ * Deadline to pay for the contract.
+ */
+ pay_deadline: TalerProtocolTimestamp;
+ /**
+ * Maximum deposit fee covered by the merchant.
+ */
+ max_fee: string;
+ /**
+ * Information about the merchant.
+ */
+ merchant: MerchantInfo;
+ /**
+ * Public key of the merchant.
+ */
+ merchant_pub: string;
+ /**
+ * Time indicating when the order should be delivered.
+ * May be overwritten by individual products.
+ */
+ delivery_date?: TalerProtocolTimestamp;
+ /**
+ * Delivery location for (all!) products.
+ */
+ delivery_location?: Location;
+ /**
+ * List of accepted exchanges.
+ */
+ exchanges: ExchangeHandle[];
+ /**
+ * Products that are sold in this contract.
+ */
+ products?: Product[];
+ /**
+ * Deadline for refunds.
+ */
+ refund_deadline: TalerProtocolTimestamp;
+ /**
+ * Deadline for the wire transfer.
+ */
+ wire_transfer_deadline: TalerProtocolTimestamp;
+ /**
+ * Time when the contract was generated by the merchant.
+ */
+ timestamp: TalerProtocolTimestamp;
+ /**
+ * Order id to uniquely identify the purchase within
+ * one merchant instance.
+ */
+ order_id: string;
+ /**
+ * Base URL of the merchant's backend.
+ */
+ merchant_base_url: string;
+ /**
+ * Fulfillment URL to view the product or
+ * delivery status.
+ */
+ fulfillment_url?: string;
+ /**
+ * URL meant to share the shopping cart.
+ */
+ public_reorder_url?: string;
+ /**
+ * Plain text fulfillment message in the merchant's default language.
+ */
+ fulfillment_message?: string;
+ /**
+ * Internationalized fulfillment messages.
+ */
+ fulfillment_message_i18n?: InternationalizedString;
+ /**
+ * Share of the wire fee that must be settled with one payment.
+ */
+ wire_fee_amortization?: number;
+ /**
+ * Maximum wire fee that the merchant agrees to pay for.
+ */
+ max_wire_fee?: string;
+ minimum_age?: number;
+ /**
+ * Extra data, interpreted by the mechant only.
+ */
+ extra?: any;
+}
+```
+```typescript
+export interface TalerProtocolDuration {
+ readonly d_us: number | "forever";
+}
+```
+```typescript
+export interface AuditorHandle {
+ /**
+ * Official name of the auditor.
+ */
+ name: string;
+ /**
+ * Master public signing key of the auditor.
+ */
+ auditor_pub: string;
+ /**
+ * Base URL of the auditor.
+ */
+ url: string;
+}
+```
+```typescript
+/**
+ * Information about an exchange as stored inside a
+ * merchant's contract terms.
+ */
+export interface ExchangeHandle {
+ /**
+ * Master public signing key of the exchange.
+ */
+ master_pub: string;
+ /**
+ * Base URL of the exchange.
+ */
+ url: string;
+}
+```
+```typescript
+/**
+ * Forced coin selection for deposits/payments.
+ */
+export interface ForcedCoinSel {
+ coins: {
+ value: AmountString;
+ contribution: AmountString;
+ }[];
+}
+```
+```typescript
+// Enum value:
+// ProviderPaymentType.Pending = "pending"
+```
+```typescript
+export interface TalerErrorDetail {
+ code: TalerErrorCode;
+ hint?: string;
+ [x: string]: unknown;
+}
+```
+```typescript
+export interface BackupRecovery {
+ walletRootPriv: string;
+ providers: {
+ url: string;
+ }[];
+}
+```
+```typescript
+export interface AbsoluteTime {
+ /**
+ * Timestamp in milliseconds.
+ */
+ readonly t_ms: number | "never";
+}
+```
+```typescript
+export interface Duration {
+ /**
+ * Duration in milliseconds.
+ */
+ readonly d_ms: number | "forever";
+}
+```
diff --git a/extract-tsdefs/package.json b/extract-tsdefs/package.json
new file mode 100644
index 00000000..cf3ba343
--- /dev/null
+++ b/extract-tsdefs/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "extract-tsdefs",
+ "version": "0.0.1",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "compile": "tsc",
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "GPL-3.0",
+ "devDependencies": {
+ "@types/node": "^18.8.1",
+ "@types/prettier": "^2.7.1",
+ "prettier": "^2.7.1",
+ "typescript": "^4.8.4"
+ }
+}
diff --git a/extract-tsdefs/pnpm-lock.yaml b/extract-tsdefs/pnpm-lock.yaml
new file mode 100644
index 00000000..6d064c10
--- /dev/null
+++ b/extract-tsdefs/pnpm-lock.yaml
@@ -0,0 +1,41 @@
+lockfileVersion: '6.1'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+devDependencies:
+ '@types/node':
+ specifier: ^18.8.1
+ version: 18.8.1
+ '@types/prettier':
+ specifier: ^2.7.1
+ version: 2.7.1
+ prettier:
+ specifier: ^2.7.1
+ version: 2.7.1
+ typescript:
+ specifier: ^4.8.4
+ version: 4.8.4
+
+packages:
+
+ /@types/node@18.8.1:
+ resolution: {integrity: sha512-vuYaNuEIbOYLTLUAJh50ezEbvxrD43iby+lpUA2aa148Nh5kX/AVO/9m1Ahmbux2iU5uxJTNF9g2Y+31uml7RQ==}
+ dev: true
+
+ /@types/prettier@2.7.1:
+ resolution: {integrity: sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==}
+ dev: true
+
+ /prettier@2.7.1:
+ resolution: {integrity: sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==}
+ engines: {node: '>=10.13.0'}
+ hasBin: true
+ dev: true
+
+ /typescript@4.8.4:
+ resolution: {integrity: sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==}
+ engines: {node: '>=4.2.0'}
+ hasBin: true
+ dev: true
diff --git a/extract-tsdefs/tsconfig.json b/extract-tsdefs/tsconfig.json
new file mode 100644
index 00000000..83ee9e28
--- /dev/null
+++ b/extract-tsdefs/tsconfig.json
@@ -0,0 +1,103 @@
+{
+ "compilerOptions": {
+ /* Visit https://aka.ms/tsconfig to read more about this file */
+
+ /* Projects */
+ // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
+ // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
+ // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
+ // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
+ // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
+ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
+
+ /* Language and Environment */
+ "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
+ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
+ // "jsx": "preserve", /* Specify what JSX code is generated. */
+ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
+ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
+ // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
+ // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
+ // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
+ // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
+ // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
+ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
+ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
+
+ /* Modules */
+ "module": "commonjs", /* Specify what module code is generated. */
+ // "rootDir": "./", /* Specify the root folder within your source files. */
+ // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
+ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
+ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
+ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
+ // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
+ // "types": [], /* Specify type package names to be included without being referenced in a source file. */
+ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
+ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
+ // "resolveJsonModule": true, /* Enable importing .json files. */
+ // "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
+
+ /* JavaScript Support */
+ // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
+ // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
+ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
+
+ /* Emit */
+ // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
+ // "declarationMap": true, /* Create sourcemaps for d.ts files. */
+ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
+ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
+ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
+ "outDir": "./dist", /* Specify an output folder for all emitted files. */
+ // "removeComments": true, /* Disable emitting comments. */
+ // "noEmit": true, /* Disable emitting files from a compilation. */
+ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
+ // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
+ // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
+ // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
+ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
+ // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
+ // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
+ // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
+ // "newLine": "crlf", /* Set the newline character for emitting files. */
+ // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
+ // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
+ // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
+ // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
+ // "declarationDir": "./", /* Specify the output directory for generated declaration files. */
+ // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
+
+ /* Interop Constraints */
+ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
+ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
+ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
+ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
+ "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
+
+ /* Type Checking */
+ "strict": true, /* Enable all strict type-checking options. */
+ // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
+ // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
+ // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
+ // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
+ // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
+ // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
+ // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
+ // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
+ // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
+ // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
+ // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
+ // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
+ // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
+ // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
+ // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
+ // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
+ // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
+ // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
+
+ /* Completeness */
+ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
+ "skipLibCheck": true /* Skip type checking all .d.ts files. */
+ }
+}
diff --git a/frags/about-taler.rst b/frags/about-taler.rst
new file mode 100644
index 00000000..7838cde7
--- /dev/null
+++ b/frags/about-taler.rst
@@ -0,0 +1,26 @@
+..
+ This file is part of GNU TALER.
+
+ Copyright (C) 2014-2023 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+
+GNU Taler is an open protocol for an electronic payment system with a
+free software reference implementation. GNU Taler offers secure, fast
+and easy payment processing using well understood cryptographic
+techniques. GNU Taler allows customers to remain anonymous, while
+ensuring that merchants can be held accountable by governments. Hence,
+GNU Taler is compatible with anti-money-laundering (AML) and
+know-your-customer (KYC) regulation, as well as data protection
+regulation (such as GDPR).
+
diff --git a/frags/apt-install-libeufin-bank.rst b/frags/apt-install-libeufin-bank.rst
new file mode 100644
index 00000000..97b1bd71
--- /dev/null
+++ b/frags/apt-install-libeufin-bank.rst
@@ -0,0 +1,6 @@
+
+To install libeufin-nexus, you can now simply run:
+
+.. code-block:: console
+
+ # apt install libeufin-bank
diff --git a/frags/apt-install-libeufin-nexus.rst b/frags/apt-install-libeufin-nexus.rst
new file mode 100644
index 00000000..25ff8070
--- /dev/null
+++ b/frags/apt-install-libeufin-nexus.rst
@@ -0,0 +1,6 @@
+
+To install libeufin-nexus, you can now simply run:
+
+.. code-block:: console
+
+ # apt install libeufin-nexus
diff --git a/frags/apt-install-taler-merchant.rst b/frags/apt-install-taler-merchant.rst
index d9605f79..1593dcfd 100644
--- a/frags/apt-install-taler-merchant.rst
+++ b/frags/apt-install-taler-merchant.rst
@@ -9,5 +9,6 @@ Note that the package does not complete the integration of the backend with
the HTTP reverse proxy (typically with TLS certificates). A configuration
fragment for Nginx or Apache will be placed in
``/etc/{apache,nginx}/conf-available/taler-merchant.conf``. You must
-furthermore still configure the instances, and may need to extend the fragment
-with access control restrictions for non-default instances.
+furthermore still configure the database and the instances, and may need to
+extend the fragment with access control restrictions for non-default
+instances.
diff --git a/frags/common-conf-syntax.rst b/frags/common-conf-syntax.rst
new file mode 100644
index 00000000..2ca15058
--- /dev/null
+++ b/frags/common-conf-syntax.rst
@@ -0,0 +1,61 @@
+The configuration file is line-oriented. Blank lines and whitespace at the
+beginning and end of a line are ignored. Comments start with ``#`` or ``%``
+in the first column (after any beginning-of-line whitespace) and go to the end
+of the line.
+
+The file is split into sections. Every section begins with ``[SECTIONNAME]``
+and contains a number of options of the form ``OPTION=VALUE``. There may be
+whitespace around the ``=`` (equal sign). Section names and options are
+*case-insensitive*.
+
+The values, however, are *case-sensitive*. In particular, boolean values are
+one of ``YES`` or ``NO``. Values can include whitespace by surrounding the
+entire value with ``"`` (double quote). Note, however, that there are no
+escape characters in such strings; all characters between the double quotes
+(including other double quotes) are taken verbatim.
+
+Values that represent a time duration are represented as a series
+of one or more ``NUMBER UNIT`` pairs, e.g. ``60 s``, ``4 weeks 1 day``,
+``5 years 2 minutes``.
+
+Values that represent an amount are in the usual amount syntax:
+``CURRENCY:VALUE.FRACTION``, e.g. ``EUR:1.50``.
+The ``FRACTION`` portion may extend up to 8 places.
+
+Values that represent filenames can begin with a ``/bin/sh``-like variable
+reference. This can be simple, such as ``$TMPDIR/foo``, or complex, such as
+``${TMPDIR:-${TMP:-/tmp}}/foo``. The variables are expanded either using
+key-values from the ``[PATHS]`` section (see below) or from the environment
+(``getenv()``). The values from ``[PATHS]`` take precedence over those from
+the environment. If the variable name is found in neither ``[PATHS]`` nor the
+environment, a warning is printed and the value is left unchanged. Variables (including those from the environment) are expanded recursively, so if ``FOO=$BAR`` and ``BAR=buzz`` then the result is ``FOO=buzz``. Recursion is bounded to at most 128 levels to avoid undefined behavior for mutually recursive expansions like if ``BAR=$FOO`` in the example above.
+
+The ``[PATHS]`` section is special in that it contains paths that can be
+referenced using ``$`` in other configuration values that specify
+*filenames*. Note that configuration options that are not specifically
+retrieved by the application as *filenames* will not see “$”-expressions
+expanded. To expand ``$``-expressions when using ``taler-config``, you must pass
+the ``-f`` command-line option.
+
+The system automatically pre-populates the ``[PATHS]`` section with a few values
+at run-time (in addition to the values that are in the actual configuration
+file and automatically overwriting those values if they are present).
+These automatically generated values refer to installation properties
+from `GNU autoconf
+<https://www.gnu.org/prep/standards/html_node/Directory-Variables.html>`_. The
+values are usually dependent on an ``INSTALL_PREFIX`` which is determined by
+the ``--prefix`` option given to configure. The canonical values are:
+
+* LIBEXECDIR = $INSTALL_PREFIX/taler/libexec/
+* DOCDIR = $INSTALL_PREFIX/share/doc/taler/
+* ICONDIR = $INSTALL_PREFIX/share/icons/
+* LOCALEDIR = $INSTALL_PREFIX/share/locale/
+* PREFIX = $INSTALL_PREFIX/
+* BINDIR = $INSTALL_PREFIX/bin/
+* LIBDIR = $INSTALL_PREFIX/lib/taler/
+* DATADIR = $INSTALL_PREFIX/share/taler/
+
+Note that on some platforms, the given paths may differ depending
+on how the system was compiled or installed, the above are just the
+canonical locations of the various resources. These
+automatically generated values are never written to disk.
diff --git a/frags/configuration-format.rst b/frags/configuration-format.rst
index f9b28e19..5a74c775 100644
--- a/frags/configuration-format.rst
+++ b/frags/configuration-format.rst
@@ -1,16 +1,22 @@
Configuration format
--------------------
-In Taler realm, any component obeys to the same pattern to get
-configuration values. According to this pattern, once the component has
-been installed, the installation deploys default values in
-${prefix}/share/taler/config.d/, in .conf files. In order to override
-these defaults, the user can write a custom .conf file and either pass
-it to the component at execution time, or name it taler.conf and place
-it under $HOME/.config/.
+All GNU Taler components are designed to possibly share the same
+configuration files. When installing a GNU Taler component, the
+installation deploys default values in configuration files located
+at ${prefix}/share/taler/config.d/ where ${prefix} is the installation
+prefix. Different components must be installed to the same prefix.
+
+In order to override these defaults, the user can write a custom configuration
+file and either pass it to the component at execution time using the *-c*
+option, or name it taler.conf and place it under $HOME/.config/ which is where
+components will look by default. Note that the systemd service files pass ``-c
+/etc/taler/taler.conf``, thus making ``/etc/taler/taler.conf``
+the primary location for the configuration.
A config file is a text file containing sections, and each section
-contains its values. The right format follows:
+contains maps options to their values. Configuration files follow
+basically the INI syntax:
.. code-block:: ini
@@ -22,48 +28,37 @@ contains its values. The right format follows:
value21 = string
value22 = /path22
-Throughout any configuration file, it is possible to use ``$``-prefixed
-variables, like ``$VAR``, especially when they represent filesystem
-paths. It is also possible to provide defaults values for those
+Comments start with a hash (``#``). Throughout the configuration, it is
+possible to use ``$``-substitution for options relating to names of files or
+directories. It is also possible to provide defaults values for those
variables that are unset, by using the following syntax:
-``${VAR:-default}``. However, there are two ways a user can set
-``$``-prefixable variables:
+``${VAR:-default}``. There are two ways a user can set the value
+of ``$``-prefixable variables:
-by defining them under a ``[paths]`` section, see example below,
+(1) by defining them under a ``[paths]`` section:
-.. code-block:: ini
+ .. code-block:: ini
- [paths]
- TALER_DEPLOYMENT_SHARED = ${HOME}/shared-data
- ..
- [section-x]
- path-x = ${TALER_DEPLOYMENT_SHARED}/x
+ [paths]
+ TALER_DEPLOYMENT_SHARED = ${HOME}/shared-data
+ ..
+ [section-x]
+ path-x = ${TALER_DEPLOYMENT_SHARED}/x
-or by setting them in the environment:
+(2) or by setting them in the environment:
-.. code-block:: console
+ .. code-block:: console
- $ export VAR=/x
+ $ export VAR=/x
The configuration loader will give precedence to variables set under
-``[path]``, though.
+``[path]`` over environment variables.
-The utility ``taler-config``, which gets installed along with the
-exchange, serves to get and set configuration values without directly
-editing the .conf. The option ``-f`` is particularly useful to resolve
+The utility ``taler-config``, which gets installed along with the exchange,
+can be used get and set configuration values without directly editing the
+configuration file. The option ``-f`` is particularly useful to resolve
pathnames, when they use several levels of ``$``-expanded variables. See
``taler-config --help``.
-Note that, in this stage of development, the file
-``$HOME/.config/taler.conf`` can contain sections for *all* the
-component. For example, both an exchange and a bank can read values from
-it.
-
-The repository ``git://taler.net/deployment`` contains examples of
-configuration file used in our demos. See under ``deployment/config``.
-
- **Note**
-
- Expectably, some components will not work just by using default
- values, as their work is often interdependent. For example, a
- merchant needs to know an exchange URL, or a database name.
+The repository ``git://git.taler.net/deployment`` contains example code
+for generating configuration files under ``deployment/netzbon/``.
diff --git a/frags/db-stores-sensitive-data.rst b/frags/db-stores-sensitive-data.rst
index 514db015..0e3dab86 100644
--- a/frags/db-stores-sensitive-data.rst
+++ b/frags/db-stores-sensitive-data.rst
@@ -1,6 +1,5 @@
.. note::
- The Taler merchant backend stores private keys and other sensitive
- business and customer data in the database. The backend operator
- SHOULD ensure that backup operations are encrypted and secured from
- unauthorized access.
+ Taler may store sensitive business and customer data in the database. Any
+ operator SHOULD thus ensure that backup operations are encrypted and
+ secured from unauthorized access.
diff --git a/frags/deploying-tos.rst b/frags/deploying-tos.rst
new file mode 100644
index 00000000..5b389f44
--- /dev/null
+++ b/frags/deploying-tos.rst
@@ -0,0 +1,45 @@
+..
+ This file is part of GNU TALER.
+ Copyright (C) 2014-2024 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+
+Configuring exchange terms
+==========================
+
+You can use your own terms of service and privacy policy. You can use the default templates in ``/usr/share/taler/terms`` as a guide.
+Assuming you have custom terms of service and privacy policy ``rst`` teamplte files at ``TOS_PATH`` and ``PRIVACY_PATH``, the following commands generate the terms files:
+
+.. code-block:: console
+
+ # taler-terms-generator -i "$TOS_PATH"
+ # taler-terms-generator -i "$PRIVACY_PATH"
+
+You now have to specify the terms file names in the exchange config:
+
+.. code-block:: console
+
+ # TERMS_ETAG="$(basename "$TOS_PATH" .rst)"
+ # PRIVACY_ETAG="$(basename "$PRIVACY_PATH" .rst)"
+
+.. code-block:: ini
+
+ [exchange]
+ TERMS_ETAG=${TERMS_ETAG}
+ PRIVACY_ETAG=${PRIVACY_ETAG}
+
+Make sure to restart taler-exchange after changing these configuration options:
+
+.. code-block:: console
+
+ # systemctl restart taler-exchange.target
diff --git a/frags/ebics-setup.rst b/frags/ebics-setup.rst
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/frags/ebics-setup.rst
diff --git a/frags/install-before-check.rst b/frags/install-before-check.rst
new file mode 100644
index 00000000..9cde7481
--- /dev/null
+++ b/frags/install-before-check.rst
@@ -0,0 +1,6 @@
+Please note that unlike most packages, if you want to run the ``make check``
+command, you should run it only *after* having done ``make install``. The
+latter ensures that necessary binaries are copied to the right place.
+
+In any case, if ``make check`` fails, please consider filing a
+bug report with the Taler `bug tracker <https://bugs.taler.net>`__.
diff --git a/frags/installing-challenger.rst b/frags/installing-challenger.rst
new file mode 100644
index 00000000..2e7526e4
--- /dev/null
+++ b/frags/installing-challenger.rst
@@ -0,0 +1 @@
+TBD.
diff --git a/frags/installing-debian.rst b/frags/installing-debian.rst
index 0110b243..0032e65e 100644
--- a/frags/installing-debian.rst
+++ b/frags/installing-debian.rst
@@ -1,6 +1,6 @@
To install the GNU Taler Debian packages, first ensure that you have
the right Debian distribution. At this time, the packages are built for
-Bullseye.
+Debian bookworm.
You need to add a file to import the GNU Taler packages. Typically,
this is done by adding a file ``/etc/apt/sources.list.d/taler.list`` that
@@ -8,19 +8,20 @@ looks like this:
.. code-block::
- deb https://deb.taler.net/apt/debian bullseye main
+ deb [signed-by=/etc/apt/keyrings/taler-systems.gpg] https://deb.taler.net/apt/debian bookworm main
Next, you must import the Taler Systems SA public package signing key
into your keyring and update the package lists:
.. code-block:: console
- # wget -O - https://taler.net/taler-systems.gpg.key | apt-key add -
+ # wget -O /etc/apt/keyrings/taler-systems.gpg \
+ https://taler.net/taler-systems.gpg
# apt update
.. note::
- You may want to verify the correctness of the Taler Systems key out-of-band.
+ You may want to verify the correctness of the Taler Systems SA key out-of-band.
Now your system is ready to install the official GNU Taler binary packages
using apt.
diff --git a/frags/installing-gnunet.rst b/frags/installing-gnunet.rst
index 99ff472d..a39358d0 100644
--- a/frags/installing-gnunet.rst
+++ b/frags/installing-gnunet.rst
@@ -2,6 +2,13 @@ Before you install GNUnet, you must download and install the dependencies
mentioned in the previous section, otherwise the build may succeed, but could
fail to export some of the tooling required by GNU Taler.
+On Ubuntu, you also need to install pkg-config, for example:
+
+.. code-block:: console
+
+ $ apt-get install pkg-config
+
+
To install GNUnet, unpack the tarball and change
into the resulting directory, then proceed as follows:
diff --git a/frags/installing-taler-merchant.rst b/frags/installing-taler-merchant.rst
index 249d5d77..f83e4aca 100644
--- a/frags/installing-taler-merchant.rst
+++ b/frags/installing-taler-merchant.rst
@@ -1,7 +1,3 @@
-GNU Taler merchant has these additional dependencies:
-
-- libqrencode >= 4.0.0
-
The following steps assume all dependencies are installed.
First, unpack the GNU Taler merchant tarball and change into
diff --git a/frags/installing-trisquel.rst b/frags/installing-trisquel.rst
new file mode 100644
index 00000000..f431b120
--- /dev/null
+++ b/frags/installing-trisquel.rst
@@ -0,0 +1,4 @@
+To install the GNU Taler Trisquel packages, first ensure that you have
+the right Trisquel distribution. Packages are currently available for
+Trisquel GNU/Linux 10.0. Simply follow the same instructions provided
+for Ubuntu.
diff --git a/frags/installing-ubuntu.rst b/frags/installing-ubuntu.rst
index 12831043..f31b4ec6 100644
--- a/frags/installing-ubuntu.rst
+++ b/frags/installing-ubuntu.rst
@@ -1,13 +1,21 @@
To install the GNU Taler Ubuntu packages, first ensure that you have
the right Ubuntu distribution. At this time, the packages are built for
-Ubuntu 20.04 LTS (Focal Fossa).
+Ubuntu Lunar and Ubuntu Jammy. Make sure to have ``universe`` in your
+``/etc/apt/sources.list`` (after ``main``) as we depend on some packages
+from Ubuntu ``universe``.
A typical ``/etc/apt/sources.list.d/taler.list`` file for this setup
-would look like this:
+would look like this for Ubuntu Lunar:
.. code-block::
- deb https://deb.taler.net/apt/ubuntu/ focal-fossa main
+ deb [signed-by=/etc/apt/keyrings/taler-systems.gpg] https://deb.taler.net/apt/ubuntu/ lunar taler-lunar
+
+For Ubuntu Mantic use this instead:
+
+.. code-block::
+
+ deb [signed-by=/etc/apt/keyrings/taler-systems.gpg] https://deb.taler.net/apt/ubuntu/ mantic taler-mantic
The last line is crucial, as it adds the GNU Taler packages.
@@ -16,7 +24,8 @@ into your keyring and update the package lists:
.. code-block:: console
- # wget -O - https://taler.net/taler-systems.gpg.key | apt-key add -
+ # wget -O /etc/apt/keyrings/taler-systems.gpg \
+ https://taler.net/taler-systems.gpg
# apt update
.. note::
diff --git a/frags/legal.rst b/frags/legal.rst
new file mode 100644
index 00000000..be9b7f91
--- /dev/null
+++ b/frags/legal.rst
@@ -0,0 +1,183 @@
+..
+ This file is part of GNU TALER.
+
+ Copyright (C) 2014-2023 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Christian Grothoff
+
+
+The service has well-known API endpoints to return its legal conditions to the
+user in various languages and various formats. This section describes how to
+setup and configure the legal conditions.
+
+
+Terms of Service
+----------------
+
+The service has an endpoint "/terms" to return the terms of service (in legal
+language) of the service operator. Client software show these terms of
+service to the user when the user is first interacting with the service.
+Terms of service are optional for experimental deployments, if none are
+configured, the service will return a simple statement saying that there are
+no terms of service available.
+
+To configure the terms of service response, there are two options
+in the configuration file for the service:
+
+- ``TERMS_ETAG``: The current "Etag" to return for the terms of service.
+ This value must be changed whenever the terms of service are
+ updated. A common value to use would be a version number.
+ Note that if you change the ``TERMS_ETAG``, you MUST also provide
+ the respective files in ``TERMS_DIR`` (see below).
+- ``TERMS_DIR``: The directory that contains the terms of service.
+ The files in the directory must be readable to the service
+ process.
+
+
+Privacy Policy
+--------------
+
+The service has an endpoint "/pp" to return the terms privacy policy (in legal
+language) of the service operator. Clients should show the privacy policy to
+the user when the user explicitly asks for it, but it should not be shown by
+default. Privacy policies are optional for experimental deployments, if none
+are configured, the service will return a simple statement saying that there
+is no privacy policy available.
+
+To configure the privacy policy response, there are two options
+in the configuration file for the service:
+
+- ``PRIVACY_ETAG``: The current "Etag" to return for the privacy policy.
+ This value must be changed whenever the privacy policy is
+ updated. A common value to use would be a version number.
+ Note that if you change the ``PRIVACY_ETAG``, you MUST also provide
+ the respective files in ``PRIVACY_DIR`` (see below).
+- ``PRIVACY_DIR``: The directory that contains the privacy policy.
+ The files in the directory must be readable to the service
+ process.
+
+
+Legal policies directory layout
+-------------------------------
+
+The ``TERMS_DIR`` and ``PRIVACY_DIR`` directory structures must follow a
+particular layout. You may use the same directory for both the terms of
+service and the privacy policy, as long as you use different ETAGs. Inside of
+the directory, there should be sub-directories using two-letter language codes
+like "en", "de", or "jp". Each of these directories would then hold
+translations of the current terms of service into the respective language.
+Empty directories are permitted in case translations are not available.
+
+Then, inside each language directory, files with the name of the value set as
+the ``TERMS_ETAG`` or ``PRIVACY_ETAG`` must be provided. The extension of each
+of the files should be typical for the respective mime type. The set of
+supported mime types is currently hard-coded in the service, and includes
+".epub", ".html", ".md", ".pdf" and ".txt" files. If other files are present,
+the service may show a warning on startup.
+
+Example
+^^^^^^^
+
+A sample file structure for a ``TERMS_ETAG`` of "tos-v0" would be:
+
+- TERMS_DIR/en/tos-v0.txt
+- TERMS_DIR/en/tos-v0.html
+- TERMS_DIR/en/tos-v0.pdf
+- TERMS_DIR/en/tos-v0.epub
+- TERMS_DIR/en/tos-v0.md
+- TERMS_DIR/de/tos-v0.txt
+- TERMS_DIR/de/tos-v0.html
+- TERMS_DIR/de/tos-v0.pdf
+- TERMS_DIR/de/tos-v0.epub
+- TERMS_DIR/de/tos-v0.md
+
+If the user requests an HTML format with language preferences "fr" followed by
+"en", the service would return ``TERMS_DIR/en/tos-v0.html`` lacking a version in
+French.
+
+
+Generating the Legal Terms
+--------------------------
+
+The ``taler-terms-generator`` script can be used to generate directories with
+terms of service and privacy policies in multiple languages and all required
+data formats from a single source file in ``.rst`` format and GNU gettext
+translations in ``.po`` format.
+
+To use the tool, you need to first write your legal conditions in English in
+reStructuredText (rst). You should find a templates in
+``$PREFIX/share/terms/*.rst`` where ``$PREFIX`` is the location where you
+installed the service to. Whenever you make substantive changes to the legal
+terms, you must use a fresh filename and change the respective ``ETAG``. The
+resulting file must be called ``$ETAG.rst`` and the first line of the file should be the title of the document.
+
+Once you have written the ``$ETAG.rst`` file in English, you can
+generate the first set of outputs:
+
+.. code-block:: shell-session
+
+ $ taler-terms-generator -i $ETAG
+
+Afterwards, you should find the terms in various formats for all configured
+languages (initially only English) in ``$PREFIX/share/terms/``. The generator
+has a few options which are documented in its man page.
+
+
+Adding translations
+-------------------
+
+Translations must be available in subdirectories
+``locale/$LANGUAGE/LC_MESSAGES/$ETAG.po``.
+To start translating, you first need to add a new
+language:
+
+.. code-block:: shell-session
+
+ $ taler-terms-generator -i $ETAG -l $LANGUAGE
+
+Here, ``$LANGUAGE`` should be a two-letter language
+code like ``de`` or ``fr``. The command will generate
+a file ``locale/$LANGUAGE/LC_MESSAGES/$ETAG.po``
+which contains each English sentence or paragraph
+in the original document and an initially empty
+translation. Translators should update the ``.po``
+file. Afterwards, simply re-run
+
+.. code-block:: shell-session
+
+ $ taler-terms-generator -i $ETAG
+
+to make the current translation(s) available to the
+service.
+
+.. note::
+
+ You must restart the service whenever adding or updating legal documents or their translations.
+
+
+Updating legal documents
+------------------------
+
+When making minor changes without legal implications, edit the ``.rst`` file,
+then re-run the step to add a new language for each existing translation to
+produce an updated ``.po`` file. Translate the sentences that have changed and
+finally run the generator (without ``-l``) on the ETAG (``-i $ETAG``) to
+create the final files.
+
+When making major changes with legal implications, you should first rename (or
+copy) the existing ``.rst`` file and the associated translation files to a new
+unique name. Afterwards, make the major changes, update the ``.po`` files,
+complete the translations and re-create the final files. Finally, do not
+forget to update the ``ETAG`` configuration option to the new name and to
+restart the service.
diff --git a/frags/libeufin-config-cli.rst b/frags/libeufin-config-cli.rst
new file mode 100644
index 00000000..5475324e
--- /dev/null
+++ b/frags/libeufin-config-cli.rst
@@ -0,0 +1,51 @@
+config
+------
+
+This command inspect or change the configuration.
+
+**-h** \| **--help**
+ Print short help on options.
+
+Subcommands: **get**, **dump**, **pathsub**
+
+config get
+-----------
+
+This command lookup config value.
+
+It takes two arguments, the section name and the option name
+
+**-h** \| **--help**
+ Print short help on options.
+**-c** \| **--config** *FILENAME*
+ Specifies the configuration file.
+**-L** \| **--log** *LOGLEVEL*
+ Configure logging to use LOGLEVEL.
+**-f** \| **--filename**
+ Interpret value as path with dollar-expansion.
+
+config dump
+-----------
+
+This command dump the configuration.
+
+**-h** \| **--help**
+ Print short help on options.
+**-c** \| **--config** *FILENAME*
+ Specifies the configuration file.
+**-L** \| **--log** *LOGLEVEL*
+ Configure logging to use LOGLEVEL.
+
+config pathsub
+--------------
+
+This command substitute variables in a path.
+
+It takes one argument, a path expression.
+
+**-h** \| **--help**
+ Print short help on options.
+**-c** \| **--config** *FILENAME*
+ Specifies the configuration file.
+**-L** \| **--log** *LOGLEVEL*
+ Configure logging to use LOGLEVEL.
diff --git a/frags/list-of-dependencies.rst b/frags/list-of-dependencies.rst
index f0a183f2..5c36b086 100644
--- a/frags/list-of-dependencies.rst
+++ b/frags/list-of-dependencies.rst
@@ -1,12 +1,16 @@
+- "Sphinx RTD Theme" Python package aka ``python3-sphinx-rtd-theme``
+ on Debian-based systems (for GNUnet documentation support, can be
+ omitted if GNUnet is configured with ``--disable-documentation``)
+
- libsqlite3 >= 3.16.2
- GNU libunistring >= 0.9.3
- libcurl >= 7.26 (or libgnurl >= 7.26)
-- libqrencode >= 4.0.0
+- libqrencode >= 4.0.0 (Taler merchant only)
-- GNU libgcrypt >= 1.6
+- GNU libgcrypt >= 1.6 (1.10 or later highly recommended)
- libsodium >= 1.0
@@ -14,8 +18,31 @@
- libjansson >= 2.7
-- Postgres >= 9.6, including libpq
+- PostgreSQL >= 15, including libpq
- GNU libmicrohttpd >= 0.9.71
-- GNUnet >= 0.14.0 (from `source tarball <http://ftpmirror.gnu.org/gnunet/>`__)
+- GNUnet >= 0.20 (from `source tarball <http://ftpmirror.gnu.org/gnunet/>`__)
+
+- Python3 with ``jinja2``
+
+
+If you are on Debian stable or later, the following command may help you
+install these dependencies:
+
+.. code-block:: console
+
+ # apt-get install \
+ libqrencode-dev \
+ libsqlite3-dev \
+ libltdl-dev \
+ libunistring-dev \
+ libsodium-dev \
+ libargon2-dev \
+ libcurl4-gnutls-dev \
+ libgcrypt20-dev \
+ libjansson-dev \
+ libpq-dev \
+ libmicrohttpd-dev \
+ python3-jinja2 \
+ postgresql-15
diff --git a/frags/nexus-ebics-setup.rst b/frags/nexus-ebics-setup.rst
new file mode 100644
index 00000000..76f51bfe
--- /dev/null
+++ b/frags/nexus-ebics-setup.rst
@@ -0,0 +1,87 @@
+
+When you sign up for an EBICS-enabled bank account, the bank will provide you
+with various credentials. Those must be provided in the
+``/etc/libeufin/libeufin-nexus.conf`` configuration file together with the
+name of the *fiat* currency.
+
+.. note::
+ As legacy transactions in that bank account would likely confuse the system, it is advisable to use a fresh bank account with an empty transaction history.
+
+The following snippet shows the mandatory configuration values:
+
+.. _core-config:
+
+.. code-block:: ini
+
+ [nexus-ebics]
+ CURRENCY = CHF
+
+ # Bank
+ HOST_BASE_URL = https://ebics.postfinance.ch/ebics/ebics.aspx
+ BANK_DIALECT = postfinance
+
+ # EBICS IDs
+ HOST_ID = PFEBICS
+ USER_ID = PFC00563
+ PARTNER_ID = PFC00563
+
+ # Account information
+ IBAN = CH7789144474425692816
+ BIC = POFICHBEXXX
+ NAME = John Smith S.A.
+
+.. note::
+ Refer to the manpage ``libeufin-nexus.conf(5)``
+ for the full array of configuration values.
+
+.. warning::
+ This combination of HOST_ID, USER_ID and PARTNER_ID must never be used by another instance of libeufin-nexus or by other EBICS clients, otherwise data will be lost.
+
+Reuse existing client keys
+--------------------------
+
+If you have client keys from a previous EBICS setup you can copy the JSON file to the configured path ``CLIENT_PRIVATE_KEYS_FILE`` (``/var/lib/libeufin-nexus/client-ebics-keys.json`` with the default config).
+
+Make sure this file is accessible to the user running ``libeufin-nexus``, for the default services you should run:
+
+.. code-block:: console
+
+ $ chown libeufin-nexus:libeufin-nexus /var/lib/libeufin-nexus/client-ebics-keys.json
+
+Create new client keys
+----------------------
+
+Assuming that the configuration file exists at ``$CONFIG_FILE``, the following
+command should start the EBICS setup process:
+
+.. code-block:: console
+
+ $ libeufin-nexus ebics-setup -c "$CONFIG_FILE"
+
+If the previous command failed when running EBICS INI with an error code of
+``EBICS_INVALID_USER_OR_USER_STATE``, you need to confirm your keys to your bank to
+activate your account.
+
+To that end, the previous run should have left a PDF document that you can
+print, sign and send to the bank. Look for the message that looks like ``PDF
+file with keys created at '/tmp/libeufin-nexus-keys-$TIMESTAMP.pdf'``.
+
+Once the bank has received and processed this document you can continue.
+
+Get bank keys
+-------------
+
+Assuming that the configuration file exists at ``$CONFIG_FILE``, the following
+command will finish the EBICS setup process:
+
+.. code-block:: console
+
+ $ libeufin-nexus ebics-setup -c "$CONFIG_FILE"
+
+The EBICS setup is finished once the bank keys have been accepted.
+
+Make sure this bank keys are accessible to the user running ``libeufin-nexus``, for the default services you should run:
+
+.. code-block:: console
+
+ $ chown libeufin-nexus:libeufin-nexus /var/lib/libeufin-nexus/bank-ebics-keys.json
diff --git a/frags/regional-manual-architecture.rst b/frags/regional-manual-architecture.rst
new file mode 100644
index 00000000..ec8c9907
--- /dev/null
+++ b/frags/regional-manual-architecture.rst
@@ -0,0 +1,48 @@
+Architecture
+============
+
+There are several key components needed to operate a regional currency based
+on GNU Taler and LibEuFin technology:
+
+- LibEuFin Nexus: is responsible to drive the master (fiat) bank account both to learn
+ about incoming payments and to send fiat cash-out payments
+- LibEuFin Bank: offers basic banking operations, e.g. wire transfers, Taler withdrawals,
+ account management, cash-out's
+- Taler exchange: server side of Taler operations.
+- Taler wallet: client side of Taler operations.
+- Taler merchant backend: abstracts Taler details to the shops.
+
+.. image:: ../images/regional-currency-architecture-diagram.png
+
+In this model, the regional currency is backed by the fiat currency and users
+are offered two operations: *cash-in* to create regional currency starting
+from fiat money, and *cash-out* to convert regional currency into fiat
+currency.
+
+The design assumes that one single unit of regional currency is always backed
+by one single unit of fiat currency.
+
+
+Cash-in
++++++++
+
+One fundamental entity to create the regional currency is the *master bank account*.
+The master bank account is hosted at one fiat bank and whenever it receives a *valid*
+fiat payment of N units, it triggers the creation of N units of regional currency.
+Such trigger causes the *admin bank account* at the regional bank to wire the N units of
+regional currency to the Taler exchange (regional) bank account. At this point, the
+Taler exchange is ready to issue the regional coins to the Taler wallet that proves
+to own them.
+
+.. note::
+
+ *Valid* fiat payments are those with a Taler-relevant subject that should be generated by a Taler wallet.
+
+
+Cash-out
+++++++++
+
+Once a regional bank user confirms a cash-out operation of N units, the system sends
+a regional payment of N units to the *admin bank account*. This latter triggers then
+a fiat payment of N units to the fiat bank account owned by the user who initiated the
+cash-out.
diff --git a/frags/regional-manual-use.rst b/frags/regional-manual-use.rst
new file mode 100644
index 00000000..7566d622
--- /dev/null
+++ b/frags/regional-manual-use.rst
@@ -0,0 +1,110 @@
+.. _regional-use:
+
+Using the Regional Currency
+===========================
+
+The very first step you should check after the installation process has been
+completed successfully, is to make sure all three URLs (bank, backend and exchange),
+are available (this means to see a Website, and not any NGINX error).
+
+
+Bank backend walkthrough
++++++++++++++++++++++++++
+
+- As stated above, please visit before "https://bank.$DOMAIN_NAME", to make sure it is available.
+
+- Now login with the username "admin" and the password you have choosen during the installation process, or use the one which might
+ have been generated automatically (and shown on your terminal screen), during the installation process.
+ Once inside the Bank Administrator area, please create the "very first" customer account.
+
+- Transfer some funds from the "admin" bank account to this new customer account.
+
+- Now logout from the "admin" account, and login again using the recently "customer" account you have created, and make sure the funds you have transfered from admin, have arrived correctly.
+
+- Now, please choose the option "Send Money to a Taler Wallet", and try to send for example 100 units of your regional currency to the
+ wallet installed on your browser or mobile phone.
+
+- Now try to spend some of these funds from your wallet, and try to buy something somewhere, with the same digital currency you have choosen, during your installation process, let's say Netzbon.
+
+- Lastly, you can also try to transfer funds to another "bank account",for that you will need to know the recipient's username or the bank account ID.
+
+If you have successfully accomplished all the previous steps, for the bank administrator
+backend and your installed Wallet, you can move now to test other components such
+as the Merchant backend (https://backend.$DOMAIN_NAME).
+
+Wallet Setup
+++++++++++++
+
+This section describes the interaction between the Taler graphical wallet (Android,
+iOS, WebExtensions) and the regional currency system.
+
+You need to add your regional currency exchange to the wallet. This can
+be done by scanning a QR code with a ``taler://withdraw-exchange/exchange.$DOMAIN_NAME/$MASTER_PUBLIC_KEY``
+URL or by manually entering the URL into the respective ``Add exchange``
+dialogue.
+
+.. _regional-use-cashin:
+
+Cash-In
++++++++
+
+Next, start the withdraw process in the Taler wallet for the respective
+currency and specify the desired amount. The wallet will then show you the
+details of the fiat wire transfer that must be made for the cash-in to be
+completed. Once the money has arrived at the fiat bank account, Nexus will
+obtain the transaction data and the regional currency bank will create the
+corresponding amount in regional currency, crediting the GNU Taler exchange
+account. In turn, the exchange will issue the respective amount to your
+wallet.
+
+.. note::
+
+ Cash-in operations may be subject to conversion rates, conversion fees and
+ minimum amounts to be transferred.
+
+.. warning::
+
+ Cash-in operations can take a long time, hours at the best of times, and even days on weekends or holidays when the bank is closed.
+
+Making payments
++++++++++++++++
+
+For testing, you should be able to *deposit* regional currency directly into
+your regional currency libeufin-bank account directly from the Taler wallet.
+For this, you primarily need to know your bank account details (which should
+be accessible by clicking on your name in the bank Web site after logging in).
+
+.. note::
+
+ There may be a short delay between the wallet making the deposit and
+ the exchange crediting your bank account. This is because the wallet
+ uses a small wire transfer delay by default when initiating a deposit
+ into a bank account.
+
+For production, it is more common for a shop to configure a :ref:`Taler
+merchant backend <taler-merchant-backend-operator-manual>` or at least use an
+instance within such a setup. To configure an instance, you primarily need
+again the bank account details to :ref:`setup instance bank accounts
+<instance-bank-account>`.
+
+.. _regional-use-cashout:
+
+Cash-Out
+++++++++
+
+Regional currency accounts that have a positive balance could be eligible for
+cash-out. Cash-out operations may again be restricted by the regional
+currency operator and will *only* be made to the respective pre-configured
+fiat currency bank account. To cash-out, simply log into your regional
+currency account, select cash-out, specify the desired amount and pass the
+second-factor authorization challenge by entering the TAN you receive at the
+registered e-mail address or mobile phone number.
+
+.. note::
+
+ Cash-out operations may be subject to conversion rates, conversion fees and
+ minimum amounts to be transferred.
+
+.. warning::
+
+ Cash-out operations can take a long time, hours at the best of times, and even days on weekends or holidays when the bank is closed.
diff --git a/frags/regional-system-on.rst b/frags/regional-system-on.rst
new file mode 100644
index 00000000..1a2898e0
--- /dev/null
+++ b/frags/regional-system-on.rst
@@ -0,0 +1,44 @@
+..
+ This file is part of GNU TALER.
+ Copyright (C) 2014-2024 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+
+System ON!
+==========
+
+The last step is to enable libeufin-nexus to :ref:`import incoming bank
+transactions <receive-transaction-data>` (cash in) and to :ref:`trigger
+outgoing bank transactions <sending-payments>` (cash out).
+
+First, check that libeufin-nexus is correctly configured by running the following commands:
+
+.. code-block:: console
+
+ # sudo -u libeufin-nexus libeufin-nexus ebics-setup
+ # sudo -u libeufin-nexus libeufin-nexus ebics-fetch --transient
+ # sudo -u libeufin-nexus libeufin-nexus ebics-submit --transient
+
+If you have old transactions after the date YYYY-MM-DD that you wish to import into the database, run the following command:
+
+.. code-block:: console
+
+ # sudo -u libeufin-nexus libeufin-nexus ebics-fetch --transientt --pinned-start YYYY-MM-DD
+
+None of those commands should fail. If they all work, you can enable the services:
+
+.. code-block:: console
+
+ # systemctl enable --now libeufin-nexus.target
+
+Now that we know that libeufin-nexus is working correctly, we still need to check that communication with your bank is working properly. We will test this later, at :ref:`the end of the manual <regional-use>`. The system should only be considered functional after a successful :ref:`cash in <regional-use-cashin>` and :ref:`cash out <regional-use-cashout>`. \ No newline at end of file
diff --git a/frags/semver.rst b/frags/semver.rst
new file mode 100644
index 00000000..8e655315
--- /dev/null
+++ b/frags/semver.rst
@@ -0,0 +1,25 @@
+..
+ This file is part of GNU TALER.
+
+ Copyright (C) 2014-2023 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Christian Grothoff
+
+GNU Taler components version numbers follow the ``MAJOR.MINOR.MICRO`` format.
+The general rule for compatibility is that ``MAJOR`` and ``MINOR`` must match.
+Exceptions to this general rule are documented in the release notes.
+For example, Taler merchant 1.3.0 should be compatible with Taler exchange 1.4.x
+as the MAJOR version matches. A MAJOR version of 0 indicates experimental
+development, and you are expected to always run all of the *latest* releases
+together (no compatibility guarantees).
diff --git a/frags/using-taler-config.rst b/frags/using-taler-config.rst
index c15df84b..ba4febb4 100644
--- a/frags/using-taler-config.rst
+++ b/frags/using-taler-config.rst
@@ -1,9 +1,11 @@
Using taler-config
------------------
-The tool ``taler-config`` can be used to extract or manipulate
-configuration values; however, the configuration use the well-known INI
-file format and can also be edited by hand.
+The tool ``taler-config`` can be used to extract or manipulate configuration
+values; however, the configuration use the well-known INI file format and is
+generally better edited by hand to preserve comments and structure. Thus, ``taler-config`` should primarily be used
+to inspect or understand a configuration that is in place,
+and not to update it!
Run
@@ -17,19 +19,21 @@ Run
.. code-block:: console
- $ taler-config -s $section -o $option
+ $ taler-config -s $SECTION -o $OPTION
-to extract the respective configuration value for option ``$option`` in
-section ``$section``.
+to extract the respective configuration value for option ``$OPTION`` in
+section ``$SECTION``.
-Finally, to change a setting, run
+Finally, to change a setting and clobber your entire
+configuration file structure, inlining all values and
+removing all comments, run
.. code-block:: console
- $ taler-config -s $section -o $option -V $value
+ $ taler-config -s $SECTION -o $OPTION -V $VALUE
-to set the respective configuration value to ``$value``. Note that you
-have to manually restart the Taler backend after you change the
+to set the respective configuration value to ``$VALUE``. Note that you
+have to manually restart affected Taler components after you change the
configuration to make the new configuration go into effect.
Some default options will use $-variables, such as ``$DATADIR`` within
@@ -39,12 +43,9 @@ compare:
.. code-block:: console
- $ taler-config -s ACCOUNT-bank \
- -o WIRE_RESPONSE
- $ taler-config -f -s ACCOUNT-bank \
- -o WIRE_RESPONSE
+ $ taler-config --section exchange-offline --option MASTER_PRIV_FILE
+ $ taler-config -f --section exchange-offline --option MASTER_PRIV_FILE
While the configuration file is typically located at
-``$HOME/.config/taler.conf``, an alternative location can be specified
-to ``taler-merchant-httpd`` and ``taler-config`` using the ``-c``
-option.
+``$HOME/.config/taler.conf``, an alternative location can be specified to any
+GNU Taler component using the ``-c`` option.
diff --git a/global-licensing.rst b/global-licensing.rst
index ac5f748e..e15cfd96 100644
--- a/global-licensing.rst
+++ b/global-licensing.rst
@@ -2,28 +2,130 @@
Taler licensing information
===========================
-This file gives an overview of all Taler component's licensing and of
-runtime dependencies thereof. For "component" here is meant a set of
-source files which can be retrieved from a single repository. If
-components consist of sources under different licensing regimes, i.e.
-because we want to enable third party developments to easily integrate
-with Taler, those are described as well.
-
-All components are generally released under Lesser GPL, GPL or Affero
-GPL. The main strategy is for libraries that third parties may need
-to integrate with Taler to be under LGPL, standalone binaries and
-testcases to be under GPL, and Web servers implementing Web services
-to be under AGPL.
-
-+++++++++++++++++++++++++
-API (git://taler.net/api)
-+++++++++++++++++++++++++
-
-The specification has been jointly developed by INRIA and by individuals
+This file gives an overview of all Taler component's licensing and of runtime
+dependencies thereof. A "component" in this context is to be read as a set of
+source files which can be retrieved from a single Git repository. If
+components consist of sources under different licensing regimes, i.e. because
+we want to enable third party developments to easily integrate with Taler,
+those are described as well.
+
+All components are generally released under Lesser GPL, GPL or Affero GPL.
+The main strategy is for libraries that third parties may need to integrate
+with Taler to be under LGPL, standalone binaries and testcases to be under
+GPL, and Web servers implementing Web services and REST APIs to be under AGPL.
+Trivial code (such as build logic) is occasionally also simply put into the
+public domain. Legislations that do not have a public domain should consider
+that code to be under LGPL.
+
+The project was initially started based on code and documentation from GNUnet
+e.V. and INRIA, and is continued to be developed by the GNUnet community and
+Taler Systems SA. INRIA and GNUnet e.V. have both assigned or shared their
+copyrights with Taler Systems SA. Thus, it should generally be said that the
+code is copyright Taler Systems SA.
+
+We are also working closely with the GNU Anastasis package. Here, the same
+copyright sharing is in place between the original developers from BFH and
+GNUnet e.V., except that the copyright was assigned or shared with Anastasis
+SARL. Agreements are in place that allows developers to freely move code
+between GNU Anastasis, GNUnet and GNU Taler if this is technically warranted
+(note that all developers must sign the GNUnet e.V. copyright contributor
+agreement).
+
+Note that this file *may* be outdated. If in doubt, please contact the
+involved GNU maintainers (currently Florian Dold, Christian Grothoff and
+Martin Schanzenbach) as they generally have the responsibility and right to
+determine the appropriate license for individual components. (That right is
+technically granted and constrained by the copyright agreemnts signed by
+individual contributors and possibly subject to decision processes within
+Anastasis SARL, GNUnet e.V. and Taler Systems SA. However, in practice this
+has so far never been an issue as so far everyone agrees on the licensing
+strategy and the maintainers will just make minor adjustments to consistently
+implement that strategy when issues arise, such as code moving between
+LGPL, GPL and AGPL licensed components or developers accidentally using the
+wrong license in a header.)
+
+
+++++++++++++++++++
+Following the AGPL
+++++++++++++++++++
+
+The main goal of the AGPL is to require a service provider to make the source
+code of the service easily accessible to all users of that service.
+
+For GNUnet, GNU Taler and GNU Anastasis, we are realizing this requirement by
+implementing an ``/agpl/`` endpoint that directs users of the API to the
+source code (either a TGZ or a redirect to the Git repository) of the
+component and its dependencies (we believe it is acceptable to not include
+unmodified dependencies that are easily available and findable elsewhere
+already). The source code (as defined in the GPL) must then be downloadable
+gratis and without access control from that address in a form suitable for
+development (that is, including build system and instructions). All of the
+usual constraints of distributing code under GPL apply as well.
+
+When deploying sources that have been modified from the upstream versions
+released by GNU, you *must* thus update the ``/agpl/`` endpoint to point to
+the modified source code. Note that you *must* always make the code of the
+actually deployed version available, which includes customizations,
+extensions, integrations or security enhancements or bug fixes.
+
+.. note:
+
+ We provide this text as a clarification, the ultimate
+ license text that applies is that of the AGPLv3+.
+
++++++++++++++++++
+Following the GPL
++++++++++++++++++
+
+The GPL requires you to make the source code of the respective program
+available to all users that may be running the program. This includes again
+any customizations (branding, theming, extensions, integrations or security
+enhancements or bug fixes) you may have made. The source code for the
+modified program must be again released under the GPL and must be reasonably
+easy to find gratis for all users of your program.
+
+When shipping binaries of *unmodified* versions of the GNU releases, this is
+satisfied as GNU makes the sources available via both the Git repositories of
+the project and the FTP mirrors of the GNU project. You are still required to
+make any packaging logic you may have written to create the binaries available
+to others.
+
+.. note:
+
+ We provide this text as a clarification, the ultimate
+ license text that applies is that of the GPLv3+.
+
+
+++++++++++++++++++
+Following the LGPL
+++++++++++++++++++
+
+To follow the LGPL, you basically do everything you need to do
+under the GPL when it comes to the sources you were provided.
+
+However, you are allowed to integrate the code provided under
+the LGPL with other code that is not under the LGPLv3+.
+Nevertheless, modifications to our existing code must
+remain under the LGPLv3+, and we strongly encourage you
+to release all of your code under an appropriate FLOSS
+license.
+
+.. note:
+
+ We provide this text as a clarification, the ultimate
+ license text that applies is that of the LGPLv3+.
+
+
+
+++++++++++++++++++++++++++++++
+API (git://git.taler.net/docs)
+++++++++++++++++++++++++++++++
+
+The specification has been originally developed by INRIA and by individuals
being under the juridical subject called 'GNUnet e.V.'. For each source
file, the header indicated whose is holding the copyright, since some
parts have been taken "verbatim" from the GNUnet e.V. foundation, and
-some other have been developed at INRIA "ex novo".
+some other have been developed at INRIA or Taler Systems SA "ex novo".
Generally, GNU GPLv3 license is used for them; see COPYING.GPL.
@@ -35,9 +137,9 @@ This component has no runtime dependencies as it is supposed to generate
HTML.
-++++++++++++++++++++++++++++++++++++++++++++++++++++++
-Firefox/Android/Python Wallet (git://taler.net/wallet)
-++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+Firefox/Android/Python Wallet (git://git.taler.net/wallet-core)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
This project includes contributions from INRIA and GNUnet
e.V. developers. Please refer to each source file to obtain
@@ -59,11 +161,11 @@ project, and gives the copyright holder for each of them:
* Mozilla Firefox: Mozilla Public License, LGPL-Compatible, Mozilla Foundation
-+++++++++++++++++++++++++++++++++++++++++++++++++++
-WebExtensions Wallet (git://taler.net/wallet-webex)
-+++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+WebExtensions Wallet (git://git.taler.net/wallet-webex)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-The TypeScript code was developed 100% at INRIA, but the project
+The TypeScript code was originally developed at INRIA, but the project
involves compiling libgnunetutil and libtalerutil to JavaScript, and
thus depends on software from GNUnet e.V.
@@ -86,13 +188,13 @@ Note that these dependencies are compiled into the extension and do
not appear as separate binary files.
-+++++++++++++++++++++++++++++++++++
-Merchant (git://taler.net/merchant)
-+++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++
+Merchant (git://git.taler.net/merchant)
++++++++++++++++++++++++++++++++++++++++
This project contains code under two different licenses, and whose
copyright is held by INRIA and/or GNUnet e.V.. Please refer to each
-source file to know which party holds the copyright.
+source file to know which party holds the original copyright.
Source files are located in the following directories:
@@ -105,25 +207,21 @@ Source files are located in the following directories:
* examples/shop/
* copylib/
-In examples/blog/articles/ we included a book by Richard Stallman.
-It comes with its own permissive license (see COPYING in the
-directory).
+The merchant's backend (i.e. all the code in src/backend/) is under the GNU
+Affero GPL. Note that the use of the Affero GPL has little impact as the
+backend is not supposed to be directly accessible to the Internet). The
+license for this code is in COPYING.GPL and COPYING.AGPL.
+The merchant's frontend logic (i.e. JavaScript interacting with
+the wallet, sample code for a shop) is under the GNU GPL.
-The merchant's backend (i.e. all the code in src/backend/) is under
-the GNU Affero GPL as it depends on libgnunetutil. Note that the use
-of the Affero GPL has little impact as the backend is not supposed to
-be directly accessible to the Internet). The license for this code is
-in COPYING.GPL and COPYING.AGPL.
+The merchant library (src/lib/) is under the Lesser GNU GPL as it can be
+linked with more diverse licensed software. The license text for this code is
+in COPYING.LGPL.
-The merchant's frontend logic (i.e. JavaScript interacting with
-the wallet, sample code for a shop) is under the GNU LGPL (but
-we may choose to change this to be in the public domain or
-BSD-licensed if necessary; the code is so short that there is
-anyway the question whether it is copyrightable). Under this same
-license, it comes the merchant library (src/lib/) as it can be linked
-with more diverse licensed software. The license text for this code
-is in COPYING.LGPL.
+In taler-merchant-demos.git/talermerchantdemos/blog/articles/ we included a book
+by Richard Stallman. It comes with its own permissive license (see COPYING in
+the directory).
@@ -140,26 +238,18 @@ project, and gives the copyright holder for each of them:
* libgnunetutil (in all of its variants): GPLv3+, owned by GNUnet e.V.
* PHP: PHP License, AGPL- and LGPL-Compatible, owned by The PHP Group
-+++++++++++++++++++++++++++
-Bank (git://taler.net/bank)
-+++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++
+Libeufin (git://git.taler.net/libeufin)
++++++++++++++++++++++++++++++++++++++++
---------
Licensing
---------
-This project has been developed by INRIA. For each source file, the
-header indicated whose is holding the copyright. The licensing plan
-for the bank is to use the Affero GPLv3+.
-
-Source files of interest are located in the following directories:
-(The repository holds also scaffolded files autogenerated by Django,
-which do not have legal significance in this context.)
-
-* TalerBank/Bank/
-* TalerBank/Bank/templates/
-* TalerBank/my-static/
-* website/
+This project has been developed by Stanisci and Dold who are
+sharing their copyright with Taler Systems SA. For each source file, the
+header indicated whose is holding the copyright. The license is
+the Affero GPLv3+.
--------------------
Runtime dependencies
@@ -178,13 +268,14 @@ project, and gives the copyright holder for each of them:
.. _exchange-repo:
-+++++++++++++++++++++++++++++++++++
-Exchange (git://taler.net/exchange)
-+++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++
+Exchange (git://git.taler.net/exchange)
++++++++++++++++++++++++++++++++++++++++
-This component is based on code initially developed in Munich for
-GNUnet e.V. Most recent improvements and maintenance has been done at
-Inria. The copyright is thus shared between both institutions.
+This component is based on code initially developed in Munich for GNUnet
+e.V. but was significantly rewritten by INRIA. Most recent improvements and
+maintenance has been done at Taler Systems SA and BFH (under a copyright
+sharing agreement with GNUnet e.V.). The copyright is with Taler Systems SA.
The licensing for exported libraries to access the exchange is LGPL,
the exchange itself is under AGPL, and testcases and standalone
@@ -200,14 +291,17 @@ project, and gives the copyright holder for each of them:
* libjansson: MIT License, AGPL- and LGPL-Compatible, owned by Petri Lehtinen and other individuals
* libgcrypt: LGPL, owned by Free Software Foundation
+* libsodium: LGPL
* postgresql: PostgreSQL License, AGPL- and LGPL-Compatible, owned by The PostgreSQL Global Development Group
* libgnunetutil (in all of its variants): GPLv3+, owned by GNUnet e.V.
-* libgnunetjson: GPLv3+, GNUnet e.V.
+* libgnunetjson: LGPLv3+, GNUnet e.V.
+* libgnunetpq: AGPLv3+, GNUnet e.V.
+* libgnunetcurl: LGPLv3+, GNUnet e.V.
-+++++++++++++++++++++++++++++++++++++++++
-Web includes (git://taler.net/web-common)
-+++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++
+Web includes (git://git.taler.net/web-common)
++++++++++++++++++++++++++++++++++++++++++++++
All copyright owned by INRIA (but questionable whether creativity
threshold for copyright is even met).
diff --git a/images/Makefile b/images/Makefile
new file mode 100644
index 00000000..ad7a695d
--- /dev/null
+++ b/images/Makefile
@@ -0,0 +1,34 @@
+diagrams: regional-arch.png arch-api.png coin.png deposit.png reserve.png transaction-common-states.png transaction-withdrawal-states.png transaction-payment-states.png transaction-refund-states.png transaction-refresh-states.png transaction-deposit-states.png transaction-push-debit-states.png transaction-push-credit-states.png transaction-pull-credit-states.png transaction-pull-debit-states.png challenger.png
+
+arch-api.png: arch-api.dot
+ dot -Tpng arch-api.dot > arch-api.png
+regional-arch.png: regional-arch.dot
+ dot -Tpng regional-arch.dot > regional-arch.png
+challenger.png: challenger.dot
+ dot -Tpng challenger.dot > challenger.png
+transaction-common-states.png: transaction-common-states.dot
+ dot -Tpng transaction-common-states.dot > transaction-common-states.png
+transaction-withdrawal-states.png: transaction-withdrawal-states.dot
+ dot -Tpng transaction-withdrawal-states.dot > transaction-withdrawal-states.png
+transaction-payment-states.png: transaction-payment-states.dot
+ dot -Tpng transaction-payment-states.dot > transaction-payment-states.png
+transaction-refund-states.png: transaction-refund-states.dot
+ dot -Tpng transaction-refund-states.dot > transaction-refund-states.png
+transaction-refresh-states.png: transaction-refresh-states.dot
+ dot -Tpng transaction-refresh-states.dot > transaction-refresh-states.png
+transaction-deposit-states.png: transaction-deposit-states.dot
+ dot -Tpng transaction-deposit-states.dot > transaction-deposit-states.png
+transaction-push-debit-states.png: transaction-push-debit-states.dot
+ dot -Tpng transaction-push-debit-states.dot > transaction-push-debit-states.png
+transaction-push-credit-states.png: transaction-push-credit-states.dot
+ dot -Tpng transaction-push-credit-states.dot > transaction-push-credit-states.png
+transaction-pull-credit-states.png: transaction-pull-credit-states.dot
+ dot -Tpng transaction-pull-credit-states.dot > transaction-pull-credit-states.png
+transaction-pull-debit-states.png: transaction-pull-debit-states.dot
+ dot -Tpng transaction-pull-debit-states.dot > transaction-pull-debit-states.png
+coin.png: coin.dot
+ dot -Tpng coin.dot > coin.png
+deposit.png: deposit.dot
+ dot -Tpng deposit.dot > deposit.png
+reserve.png: reserve.dot
+ dot -Tpng reserve.dot > reserve.png
diff --git a/arch-api.dot b/images/arch-api.dot
index 1c30c06a..1c30c06a 100644
--- a/arch-api.dot
+++ b/images/arch-api.dot
diff --git a/arch.dot b/images/arch.dot
index acc9ed89..acc9ed89 100644
--- a/arch.dot
+++ b/images/arch.dot
diff --git a/auditor-db.png b/images/auditor-db.png
index 3f10f3ab..3f10f3ab 100644
--- a/auditor-db.png
+++ b/images/auditor-db.png
Binary files differ
diff --git a/backoffice-order-create.all-expanded.svg b/images/backoffice-order-create.all-expanded.svg
index efea91f6..efea91f6 100644
--- a/backoffice-order-create.all-expanded.svg
+++ b/images/backoffice-order-create.all-expanded.svg
diff --git a/backoffice-order-create.payment-section.svg b/images/backoffice-order-create.payment-section.svg
index 2e319727..b2816c7d 100644
--- a/backoffice-order-create.payment-section.svg
+++ b/images/backoffice-order-create.payment-section.svg
@@ -13,4 +13,4 @@
}
</style>
</defs>
- <rect x="0" y="0" width="812" height="755.4705463593664" fill="#ffffff"></rect><g transform="translate(10 57.28872817754791) rotate(0 396 344.09090909090924)"><path d="M0 0 C163.13469960540533 0, 326.26939921081066 0, 792 0 M0 0 C197.6944362178445 0, 395.388872435689 0, 792 0 M792 0 C792 158.56476755186247, 792 317.12953510372495, 792 688.1818181818186 M792 0 C792 266.1385155277837, 792 532.2770310555674, 792 688.1818181818186 M792 688.1818181818186 C541.9932290330529 688.1818181818186, 291.9864580661058 688.1818181818186, 0 688.1818181818186 M792 688.1818181818186 C500.6049041256308 688.1818181818186, 209.20980825126162 688.1818181818186, 0 688.1818181818186 M0 688.1818181818186 C0 513.5637151258577, 0 338.94561206989687, 0 0 M0 688.1818181818186 C0 501.1274236320436, 0 314.07302908226865, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(49 89.78872817754723) rotate(0 355.94636678200686 308.9999999999999)"><path d="M0 0 C196.37916639762955 0, 392.7583327952591 0, 711.8927335640136 0 M0 0 C222.65387708782745 0, 445.3077541756549 0, 711.8927335640136 0 M711.8927335640136 0 C711.8927335640136 136.01048013232645, 711.8927335640136 272.0209602646529, 711.8927335640136 617.9999999999998 M711.8927335640136 0 C711.8927335640136 229.1515129242092, 711.8927335640136 458.3030258484184, 711.8927335640136 617.9999999999998 M711.8927335640136 617.9999999999998 C540.7157390920328 617.9999999999998, 369.5387446200519 617.9999999999998, 0 617.9999999999998 M711.8927335640136 617.9999999999998 C560.9805535182735 617.9999999999998, 410.06837347253344 617.9999999999998, 0 617.9999999999998 M0 617.9999999999998 C0 487.54947386719266, 0 357.0989477343856, 0 0 M0 617.9999999999998 C0 469.64537168405934, 0 321.29074336811885, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(49 134.42886658585485) rotate(0 355.35899653979254 0)"><path d="M0 0 C118.45299884659751 0, 592.2649942329875 0, 710.7179930795851 0 M0 0 C118.45299884659751 0, 592.2649942329875 0, 710.7179930795851 0" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(77.19377162629803 96.83717108412088) rotate(0 45.22750865051904 13.50951557093424)"><text x="0" y="21.01903114186851" font-family="Helvetica, Segoe UI Emoji" font-size="23.494809688581313px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">payment</text></g><g transform="translate(686.884083044984 90.96346866197814) rotate(0 35.82958477508646 21.732698961937672)"><path d="M0 0 C25.693898552344557 0, 51.38779710468911 0, 71.65916955017302 0 M0 0 C18.423871399928533 0, 36.847742799857066 0, 71.65916955017302 0 M71.65916955017302 0 C71.65916955017302 14.811010985339712, 71.65916955017302 29.622021970679423, 71.65916955017302 43.46539792387543 M71.65916955017302 0 C71.65916955017302 9.170037636031626, 71.65916955017302 18.340075272063252, 71.65916955017302 43.46539792387543 M71.65916955017302 43.46539792387543 C48.850217413141436 43.46539792387543, 26.041265276109854 43.46539792387543, 0 43.46539792387543 M71.65916955017302 43.46539792387543 C50.35093945471351 43.46539792387543, 29.042709359254005 43.46539792387543, 0 43.46539792387543 M0 43.46539792387543 C0 27.43454704114484, 0 11.403696158414249, 0 0 M0 43.46539792387543 C0 26.72246210199255, 0 9.979526280109674, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(719.7768166089982 98.01191156855225) rotate(0 0 12.922145328719694)"><path d="M0 0 C0 4.307381776239908, 0 21.53690888119954, 0 25.844290657439448 M0 0 C0 4.307381776239908, 0 21.53690888119954, 0 25.844290657439448" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(719.7768166089982 98.01191156855225) rotate(0 0 12.922145328719694)"><path d="M-4.4196339974038406 13.701446047318425 C-3.1323002724435964 17.238366387949103, -1.8449665474833528 20.77528672857978, 0 25.844290657439448 M-4.4196339974038406 13.701446047318425 C-2.8705976157310924 17.957388527877995, -1.3215612340583442 22.213331008437564, 0 25.844290657439448" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(719.7768166089982 98.01191156855225) rotate(0 0 12.922145328719694)"><path d="M4.4196339974038406 13.701446047318425 C3.1323002724435964 17.238366387949103, 1.8449665474833528 20.77528672857978, 0 25.844290657439448 M4.4196339974038406 13.701446047318425 C2.8705976157310924 17.957388527877995, 1.3215612340583442 22.213331008437564, 0 25.844290657439448" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(122.41700882982559 491.89835384599746) rotate(0 41.70328719723187 13.50951557093424)"><text x="0" y="21.01903114186851" font-family="Helvetica, Segoe UI Emoji" font-size="23.494809688581313px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">max fee</text></g><g transform="translate(381.043964686653 486.02465142385245) rotate(0 99.85294117647061 18.79584775086505)"><path d="M0 0 C44.61811129907696 0, 89.23622259815392 0, 199.70588235294125 0 M0 0 C79.29353130055485 0, 158.5870626011097 0, 199.70588235294125 0 M199.70588235294125 0 C199.70588235294125 8.759946174821641, 199.70588235294125 17.519892349643282, 199.70588235294125 37.59169550173011 M199.70588235294125 0 C199.70588235294125 10.044274510345245, 199.70588235294125 20.08854902069049, 199.70588235294125 37.59169550173011 M199.70588235294125 37.59169550173011 C120.15937504977649 37.59169550173011, 40.61286774661173 37.59169550173011, 0 37.59169550173011 M199.70588235294125 37.59169550173011 C131.51639080907717 37.59169550173011, 63.32689926521306 37.59169550173011, 0 37.59169550173011 M0 37.59169550173011 C0 22.898467848158624, 0 8.205240194587144, 0 0 M0 37.59169550173011 C0 24.276735533449063, 0 10.961775565168022, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(122.41700882982559 548.2858970985903) rotate(0 66.37283737024222 13.50951557093424)"><text x="0" y="21.01903114186851" font-family="Helvetica, Segoe UI Emoji" font-size="23.49480968858131px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">max wire fee</text></g><g transform="translate(381.043964686653 537.7132327387317) rotate(0 99.85294117647061 18.79584775086505)"><path d="M0 0 C73.07786602499513 0, 146.15573204999026 0, 199.70588235294125 0 M0 0 C66.5611449872856 0, 133.1222899745712 0, 199.70588235294125 0 M199.70588235294125 0 C199.70588235294125 11.502282709924822, 199.70588235294125 23.004565419849644, 199.70588235294125 37.59169550173011 M199.70588235294125 0 C199.70588235294125 11.270341817534508, 199.70588235294125 22.540683635069016, 199.70588235294125 37.59169550173011 M199.70588235294125 37.59169550173011 C129.25950294366 37.59169550173011, 58.813123534378775 37.59169550173011, 0 37.59169550173011 M199.70588235294125 37.59169550173011 C136.2727813783705 37.59169550173011, 72.83968040379972 37.59169550173011, 0 37.59169550173011 M0 37.59169550173011 C0 24.7357254136908, 0 11.879755325651498, 0 0 M0 37.59169550173011 C0 25.50134813334909, 0 13.411000764968072, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(122.41700882982559 608.1976618044737) rotate(0 108.66349480968859 13.50951557093424)"><text x="0" y="21.01903114186851" font-family="Helvetica, Segoe UI Emoji" font-size="23.49480968858131px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">wire fee amortization</text></g><g transform="translate(381.043964686653 601.1492188978978) rotate(0 99.85294117647061 18.79584775086505)"><path d="M0 0 C63.18052968749888 0, 126.36105937499777 0, 199.70588235294125 0 M0 0 C58.832443530780886 0, 117.66488706156177 0, 199.70588235294125 0 M199.70588235294125 0 C199.70588235294125 12.2283371196383, 199.70588235294125 24.4566742392766, 199.70588235294125 37.59169550173011 M199.70588235294125 0 C199.70588235294125 13.842964280734428, 199.70588235294125 27.685928561468856, 199.70588235294125 37.59169550173011 M199.70588235294125 37.59169550173011 C137.16080129305453 37.59169550173011, 74.61572023316782 37.59169550173011, 0 37.59169550173011 M199.70588235294125 37.59169550173011 C124.86287547313776 37.59169550173011, 50.01986859333428 37.59169550173011, 0 37.59169550173011 M0 37.59169550173011 C0 25.7131450870561, 0 13.834594672382085, 0 0 M0 37.59169550173011 C0 29.765293690768495, 0 21.93889187980688, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(126.6112523026161 170.85274201837865) rotate(0 81.05709342560556 13.50951557093424)"><text x="0" y="21.01903114186851" font-family="Helvetica, Segoe UI Emoji" font-size="23.494809688581313px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">refund deadline</text></g><g transform="translate(389.96703685669763 170.11685268386054) rotate(0 69.75578583521315 18.03461720393034)"><path d="M0 0 L139.51157167042618 0 L139.51157167042618 36.06923440786065 L0 36.06923440786065" stroke="none" stroke-width="0" fill="#fff"></path><path d="M0 0 C38.588792372791914 0, 77.17758474558383 0, 139.51157167042618 0 M0 0 C51.270889713540704 0, 102.54177942708141 0, 139.51157167042618 0 M139.51157167042618 0 C139.51157167042618 11.195579849357195, 139.51157167042618 22.39115969871439, 139.51157167042618 36.06923440786065 M139.51157167042618 0 C139.51157167042618 7.478536088246398, 139.51157167042618 14.957072176492796, 139.51157167042618 36.06923440786065 M139.51157167042618 36.06923440786065 C106.073634546001 36.06923440786065, 72.63569742157583 36.06923440786065, 0 36.06923440786065 M139.51157167042618 36.06923440786065 C90.59517821844433 36.06923440786065, 41.678784766462485 36.06923440786065, 0 36.06923440786065 M0 36.06923440786065 C0 28.587188228147372, 0 21.105142048434097, 0 0 M0 36.06923440786065 C0 24.459576137678855, 0 12.849917867497062, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(423.8180831341699 176.4274732975059) rotate(0 4.884998579284627 12.212496448211482)"><text x="0" y="17.42499289642305" font-family="Virgil, Segoe UI Emoji" font-size="19.539994317138444px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(453.616574467806 175.93897343957906) rotate(0 4.884998579284627 12.212496448211482)"><text x="0" y="17.42499289642305" font-family="Virgil, Segoe UI Emoji" font-size="19.539994317138444px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(540.5695491790709 169.09997542858218) rotate(0 17.34174495646039 17.34174495646039)"><path d="M0 0 L34.68348991292074 0 L34.68348991292074 34.68348991292074 L0 34.68348991292074" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C12.350741138777865 0, 24.70148227755573 0, 34.68348991292074 0 M0 0 C13.090885427004103 0, 26.181770854008207 0, 34.68348991292074 0 M34.68348991292074 0 C34.68348991292074 8.759752021302454, 34.68348991292074 17.519504042604908, 34.68348991292074 34.68348991292074 M34.68348991292074 0 C34.68348991292074 12.827119610736222, 34.68348991292074 25.654239221472444, 34.68348991292074 34.68348991292074 M34.68348991292074 34.68348991292074 C26.26168783725121 34.68348991292074, 17.83988576158168 34.68348991292074, 0 34.68348991292074 M34.68348991292074 34.68348991292074 C25.047276653082115 34.68348991292074, 15.411063393243492 34.68348991292074, 0 34.68348991292074 M0 34.68348991292074 C0 21.65963125803831, 0 8.635772603155882, 0 0 M0 34.68348991292074 C0 22.816433409973676, 0 10.949376907026608, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(541.5465488949278 170.07697514443726) rotate(0 17.097495027496166 4.396498721356124)"><path d="M0 0 L34.19499005499228 0 L34.19499005499228 8.792997442712293 L0 8.792997442712293" stroke="none" stroke-width="0" fill="#000"></path><path d="M0 0 C8.416124992044198 0, 16.832249984088396 0, 34.19499005499228 0 M0 0 C12.612778286946597 0, 25.225556573893194 0, 34.19499005499228 0 M34.19499005499228 0 C34.19499005499228 2.784839725361176, 34.19499005499228 5.569679450722352, 34.19499005499228 8.792997442712293 M34.19499005499228 0 C34.19499005499228 2.6248021666892867, 34.19499005499228 5.249604333378573, 34.19499005499228 8.792997442712293 M34.19499005499228 8.792997442712293 C22.07788480659337 8.792997442712293, 9.96077955819446 8.792997442712293, 0 8.792997442712293 M34.19499005499228 8.792997442712293 C25.609229118108246 8.792997442712293, 17.023468181224214 8.792997442712293, 0 8.792997442712293 M0 8.792997442712293 C0 5.374793220870361, 0 1.956588999028427, 0 0 M0 8.792997442712293 C0 6.7982943981253765, 0 4.80359135353846, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(548.874046763857 161.77247755965436) rotate(0 2.9309991475707875 6.838998010998466)"><path d="M0 0 L5.861998295141533 0 L5.861998295141533 13.677996021996911 L0 13.677996021996911" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C2.06572777238916 0, 4.13145554477832 0, 5.861998295141533 0 M0 0 C1.6284420677636307 0, 3.2568841355272613 0, 5.861998295141533 0 M5.861998295141533 0 C5.861998295141533 4.0886379104374235, 5.861998295141533 8.177275820874847, 5.861998295141533 13.677996021996911 M5.861998295141533 0 C5.861998295141533 4.405838529784974, 5.861998295141533 8.811677059569949, 5.861998295141533 13.677996021996911 M5.861998295141533 13.677996021996911 C3.787286061220638 13.677996021996911, 1.7125738272997424 13.677996021996911, 0 13.677996021996911 M5.861998295141533 13.677996021996911 C4.3944272776554225 13.677996021996911, 2.9268562601693118 13.677996021996911, 0 13.677996021996911 M0 13.677996021996911 C0 9.10398929446179, 0 4.52998256692667, 0 0 M0 13.677996021996911 C0 9.353978362633276, 0 5.029960703269641, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(563.5290425017101 161.77247755965436) rotate(0 2.9309991475707875 6.838998010998466)"><path d="M0 0 L5.861998295141533 0 L5.861998295141533 13.677996021996911 L0 13.677996021996911" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C1.9136207457158667 0, 3.8272414914317334 0, 5.861998295141533 0 M0 0 C1.7752901701469925 0, 3.550580340293985 0, 5.861998295141533 0 M5.861998295141533 0 C5.861998295141533 3.1488935786452767, 5.861998295141533 6.2977871572905535, 5.861998295141533 13.677996021996911 M5.861998295141533 0 C5.861998295141533 4.449927547836239, 5.861998295141533 8.899855095672478, 5.861998295141533 13.677996021996911 M5.861998295141533 13.677996021996911 C4.27455321609603 13.677996021996911, 2.6871081370505263 13.677996021996911, 0 13.677996021996911 M5.861998295141533 13.677996021996911 C3.940863191629518 13.677996021996911, 2.019728088117503 13.677996021996911, 0 13.677996021996911 M0 13.677996021996911 C0 10.13870173751964, 0 6.599407453042369, 0 0 M0 13.677996021996911 C0 9.428222501847815, 0 5.178448981698718, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(557.2990807517933 178.205813523291) rotate(0 0.24424992896422282 12.945246235104264)"><path d="M0 0 C0.13838525821577435 7.334418685436041, 0.2767705164315487 14.668837370872081, 0.4884998579284611 25.89049247020844 M0 0 C0.18365905060197285 9.733929681904561, 0.3673181012039457 19.467859363809122, 0.4884998579284611 25.89049247020844" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(548.2098876999967 177.0974105194373) rotate(0 0.24424992896422282 13.677996021996933)"><path d="M0 0 C0.18081889830845407 10.125858305273429, 0.36163779661690815 20.251716610546858, 0.4884998579284611 27.355992043993822 M0 0 C0.1435033739142469 8.036188939197826, 0.2870067478284938 16.072377878395653, 0.4884998579284611 27.355992043993822" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(567.129978871211 178.22712166566998) rotate(0 0.7327497868926685 12.456746377175818)"><path d="M0 0 C0.49131225684945856 8.352308366440798, 0.9826245136989171 16.704616732881597, 1.4654995737853833 24.913492754351527 M0 0 C0.3645462207600854 6.197285752921455, 0.7290924415201708 12.39457150584291, 1.4654995737853833 24.913492754351527" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(575.7498470395947 186.38910449486139) rotate(0 -16.60899516956772 0)"><path d="M0 0 C-9.850046834715748 0, -19.700093669431496 0, -33.21799033913535 0 M0 0 C-11.978115758822755 0, -23.95623151764551 0, -33.21799033913535 0" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(575.2745570852853 195.08467745817006) rotate(0 -17.58599488542461 0.48849985792844564)"><path d="M0 0 C-10.91708283817915 0.3032523010605322, -21.8341656763583 0.6065046021210644, -35.17198977084917 0.9769997158569222 M0 0 C-7.292502852220365 0.20256952367278808, -14.58500570444073 0.40513904734557615, -35.17198977084917 0.9769997158569222" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(126.6112523026161 236.4338141678163) rotate(0 66.37283737024222 13.50951557093424)"><text x="0" y="21.01903114186851" font-family="Helvetica, Segoe UI Emoji" font-size="23.49480968858131px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">pay deadline</text></g><g transform="translate(389.96703685669763 235.69792483329775) rotate(0 69.75578583521315 18.03461720393034)"><path d="M0 0 L139.51157167042618 0 L139.51157167042618 36.06923440786065 L0 36.06923440786065" stroke="none" stroke-width="0" fill="#fff"></path><path d="M0 0 C47.50166837735665 0, 95.0033367547133 0, 139.51157167042618 0 M0 0 C49.76376503488774 0, 99.52753006977548 0, 139.51157167042618 0 M139.51157167042618 0 C139.51157167042618 8.446743562554808, 139.51157167042618 16.893487125109615, 139.51157167042618 36.06923440786065 M139.51157167042618 0 C139.51157167042618 11.47235701590513, 139.51157167042618 22.94471403181026, 139.51157167042618 36.06923440786065 M139.51157167042618 36.06923440786065 C96.27412265275322 36.06923440786065, 53.03667363508026 36.06923440786065, 0 36.06923440786065 M139.51157167042618 36.06923440786065 C94.95422630662594 36.06923440786065, 50.39688094282572 36.06923440786065, 0 36.06923440786065 M0 36.06923440786065 C0 26.300498294737366, 0 16.531762181614084, 0 0 M0 36.06923440786065 C0 28.404608233033215, 0 20.739982058205783, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(423.8180831341699 242.00854544694494) rotate(0 4.884998579284627 12.212496448211482)"><text x="0" y="17.42499289642305" font-family="Virgil, Segoe UI Emoji" font-size="19.539994317138444px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(453.616574467806 241.52004558901763) rotate(0 4.884998579284627 12.212496448211482)"><text x="0" y="17.42499289642305" font-family="Virgil, Segoe UI Emoji" font-size="19.539994317138444px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(540.5695491790709 234.68104757801984) rotate(0 17.34174495646039 17.34174495646039)"><path d="M0 0 L34.68348991292074 0 L34.68348991292074 34.68348991292074 L0 34.68348991292074" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C10.984645583369092 0, 21.969291166738184 0, 34.68348991292074 0 M0 0 C10.353386324163305 0, 20.70677264832661 0, 34.68348991292074 0 M34.68348991292074 0 C34.68348991292074 12.290206751947466, 34.68348991292074 24.58041350389493, 34.68348991292074 34.68348991292074 M34.68348991292074 0 C34.68348991292074 8.708414664553807, 34.68348991292074 17.416829329107614, 34.68348991292074 34.68348991292074 M34.68348991292074 34.68348991292074 C21.200573260099773 34.68348991292074, 7.717656607278801 34.68348991292074, 0 34.68348991292074 M34.68348991292074 34.68348991292074 C26.81549457038345 34.68348991292074, 18.94749922784616 34.68348991292074, 0 34.68348991292074 M0 34.68348991292074 C0 25.885278309906877, 0 17.08706670689301, 0 0 M0 34.68348991292074 C0 21.8895309879799, 0 9.095572063039057, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(541.5465488949278 235.65804729387492) rotate(0 17.097495027496166 4.396498721356124)"><path d="M0 0 L34.19499005499228 0 L34.19499005499228 8.792997442712293 L0 8.792997442712293" stroke="none" stroke-width="0" fill="#000"></path><path d="M0 0 C10.22159477609356 0, 20.44318955218712 0, 34.19499005499228 0 M0 0 C11.014596324462437 0, 22.029192648924873 0, 34.19499005499228 0 M34.19499005499228 0 C34.19499005499228 3.1120683508813407, 34.19499005499228 6.224136701762681, 34.19499005499228 8.792997442712293 M34.19499005499228 0 C34.19499005499228 2.2013565262291643, 34.19499005499228 4.402713052458329, 34.19499005499228 8.792997442712293 M34.19499005499228 8.792997442712293 C22.75997323615448 8.792997442712293, 11.324956417316677 8.792997442712293, 0 8.792997442712293 M34.19499005499228 8.792997442712293 C23.38494590658319 8.792997442712293, 12.574901758174104 8.792997442712293, 0 8.792997442712293 M0 8.792997442712293 C0 5.889444189066426, 0 2.9858909354205574, 0 0 M0 8.792997442712293 C0 5.741208897211333, 0 2.689420351710372, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(548.874046763857 227.35354970909202) rotate(0 2.9309991475707875 6.838998010998466)"><path d="M0 0 L5.861998295141533 0 L5.861998295141533 13.677996021996911 L0 13.677996021996911" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C1.3495258194194044 0, 2.699051638838809 0, 5.861998295141533 0 M0 0 C1.907111806215531 0, 3.814223612431062 0, 5.861998295141533 0 M5.861998295141533 0 C5.861998295141533 3.7040385177728417, 5.861998295141533 7.408077035545683, 5.861998295141533 13.677996021996911 M5.861998295141533 0 C5.861998295141533 4.482648574861369, 5.861998295141533 8.965297149722739, 5.861998295141533 13.677996021996911 M5.861998295141533 13.677996021996911 C4.345157887508417 13.677996021996911, 2.828317479875301 13.677996021996911, 0 13.677996021996911 M5.861998295141533 13.677996021996911 C4.040666786506207 13.677996021996911, 2.2193352778708797 13.677996021996911, 0 13.677996021996911 M0 13.677996021996911 C0 8.942165936497862, 0 4.20633585099881, 0 0 M0 13.677996021996911 C0 9.845296872419517, 0 6.012597722842125, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(563.5290425017101 227.35354970909202) rotate(0 2.9309991475707875 6.838998010998466)"><path d="M0 0 L5.861998295141533 0 L5.861998295141533 13.677996021996911 L0 13.677996021996911" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C1.5320176410516326 0, 3.0640352821032653 0, 5.861998295141533 0 M0 0 C2.169100553518035 0, 4.33820110703607 0, 5.861998295141533 0 M5.861998295141533 0 C5.861998295141533 4.243283857466258, 5.861998295141533 8.486567714932516, 5.861998295141533 13.677996021996911 M5.861998295141533 0 C5.861998295141533 4.871870315718041, 5.861998295141533 9.743740631436083, 5.861998295141533 13.677996021996911 M5.861998295141533 13.677996021996911 C4.453460484325019 13.677996021996911, 3.0449226735085038 13.677996021996911, 0 13.677996021996911 M5.861998295141533 13.677996021996911 C3.658298036524886 13.677996021996911, 1.4545977779082389 13.677996021996911, 0 13.677996021996911 M0 13.677996021996911 C0 9.954515139904878, 0 6.231034257812844, 0 0 M0 13.677996021996911 C0 9.474895524801425, 0 5.27179502760594, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(557.2990807517933 243.78688567272866) rotate(0 0.24424992896422282 12.945246235104264)"><path d="M0 0 C0.1131082943342409 5.994739599714768, 0.2262165886684818 11.989479199429535, 0.4884998579284611 25.89049247020844 M0 0 C0.11061345453975935 5.862513090607246, 0.2212269090795187 11.725026181214492, 0.4884998579284611 25.89049247020844" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(548.2098876999967 242.6784826688745) rotate(0 0.24424992896422282 13.677996021996933)"><path d="M0 0 C0.11589865333866953 6.490324586965493, 0.23179730667733905 12.980649173930987, 0.4884998579284611 27.355992043993822 M0 0 C0.14872427158435972 8.328559208724144, 0.29744854316871944 16.657118417448288, 0.4884998579284611 27.355992043993822" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(567.129978871211 243.80819381510855) rotate(0 0.7327497868926685 12.456746377175818)"><path d="M0 0 C0.29443945475956246 5.005470730912564, 0.5888789095191249 10.010941461825128, 1.4654995737853833 24.913492754351527 M0 0 C0.5640236075493323 9.588401328338653, 1.1280472150986647 19.176802656677307, 1.4654995737853833 24.913492754351527" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(575.7498470395947 251.97017664429995) rotate(0 -16.60899516956772 0)"><path d="M0 0 C-7.961641167542139 0, -15.923282335084277 0, -33.21799033913535 0 M0 0 C-11.647093252965808 0, -23.294186505931616 0, -33.21799033913535 0" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(575.2745570852853 260.66574960760863) rotate(0 -17.58599488542461 0.48849985792844564)"><path d="M0 0 C-8.236625563486276 0.22879515454128563, -16.473251126972553 0.45759030908257126, -35.17198977084917 0.9769997158569222 M0 0 C-11.186975000584102 0.3107493055717809, -22.373950001168204 0.6214986111435618, -35.17198977084917 0.9769997158569222" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(126.6112523026161 305.64423043891156) rotate(0 106.90138408304506 13.50951557093424)"><text x="0" y="21.01903114186851" font-family="Helvetica, Segoe UI Emoji" font-size="23.494809688581316px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">auto refund deadline</text></g><g transform="translate(389.96703685669763 304.90834110439346) rotate(0 69.75578583521315 18.03461720393034)"><path d="M0 0 L139.51157167042618 0 L139.51157167042618 36.06923440786065 L0 36.06923440786065" stroke="none" stroke-width="0" fill="#fff"></path><path d="M0 0 C54.233956780562394 0, 108.46791356112479 0, 139.51157167042618 0 M0 0 C31.64838368021466 0, 63.29676736042932 0, 139.51157167042618 0 M139.51157167042618 0 C139.51157167042618 9.149735435384923, 139.51157167042618 18.299470870769845, 139.51157167042618 36.06923440786065 M139.51157167042618 0 C139.51157167042618 13.305128884862302, 139.51157167042618 26.610257769724605, 139.51157167042618 36.06923440786065 M139.51157167042618 36.06923440786065 C91.61872293837436 36.06923440786065, 43.72587420632256 36.06923440786065, 0 36.06923440786065 M139.51157167042618 36.06923440786065 C96.71713609249963 36.06923440786065, 53.922700514573094 36.06923440786065, 0 36.06923440786065 M0 36.06923440786065 C0 22.783353778422555, 0 9.497473148984461, 0 0 M0 36.06923440786065 C0 25.237278543595075, 0 14.405322679329501, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(423.8180831341699 311.21896171804246) rotate(0 4.884998579284627 12.212496448211482)"><text x="0" y="17.42499289642305" font-family="Virgil, Segoe UI Emoji" font-size="19.539994317138444px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(453.616574467806 310.7304618601147) rotate(0 4.884998579284627 12.212496448211482)"><text x="0" y="17.42499289642305" font-family="Virgil, Segoe UI Emoji" font-size="19.539994317138444px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(540.5695491790709 303.89146384911646) rotate(0 17.34174495646039 17.34174495646039)"><path d="M0 0 L34.68348991292074 0 L34.68348991292074 34.68348991292074 L0 34.68348991292074" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C8.333848713997714 0, 16.667697427995428 0, 34.68348991292074 0 M0 0 C13.03855986348183 0, 26.07711972696366 0, 34.68348991292074 0 M34.68348991292074 0 C34.68348991292074 9.4416836653048, 34.68348991292074 18.8833673306096, 34.68348991292074 34.68348991292074 M34.68348991292074 0 C34.68348991292074 10.65786197503141, 34.68348991292074 21.31572395006282, 34.68348991292074 34.68348991292074 M34.68348991292074 34.68348991292074 C21.040335615093984 34.68348991292074, 7.397181317267226 34.68348991292074, 0 34.68348991292074 M34.68348991292074 34.68348991292074 C27.450049553381234 34.68348991292074, 20.216609193841723 34.68348991292074, 0 34.68348991292074 M0 34.68348991292074 C0 23.797810389582665, 0 12.912130866244592, 0 0 M0 34.68348991292074 C0 25.594766385240447, 0 16.506042857560153, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(541.5465488949278 304.86846356497153) rotate(0 17.097495027496166 4.396498721356124)"><path d="M0 0 L34.19499005499228 0 L34.19499005499228 8.792997442712293 L0 8.792997442712293" stroke="none" stroke-width="0" fill="#000"></path><path d="M0 0 C12.256912387278875 0, 24.51382477455775 0, 34.19499005499228 0 M0 0 C9.337819074833758 0, 18.675638149667517 0, 34.19499005499228 0 M34.19499005499228 0 C34.19499005499228 2.953364940224322, 34.19499005499228 5.906729880448644, 34.19499005499228 8.792997442712293 M34.19499005499228 0 C34.19499005499228 1.8197494907887624, 34.19499005499228 3.6394989815775247, 34.19499005499228 8.792997442712293 M34.19499005499228 8.792997442712293 C24.437822160950887 8.792997442712293, 14.680654266909496 8.792997442712293, 0 8.792997442712293 M34.19499005499228 8.792997442712293 C26.745579617251906 8.792997442712293, 19.29616917951153 8.792997442712293, 0 8.792997442712293 M0 8.792997442712293 C0 5.897504324214696, 0 3.002011205717099, 0 0 M0 8.792997442712293 C0 6.010860718858778, 0 3.2287239950052617, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(548.874046763857 296.5639659801868) rotate(0 2.9309991475707875 6.838998010998466)"><path d="M0 0 L5.861998295141533 0 L5.861998295141533 13.677996021996911 L0 13.677996021996911" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C1.5383239337541497 0, 3.0766478675082993 0, 5.861998295141533 0 M0 0 C1.703193236340253 0, 3.406386472680506 0, 5.861998295141533 0 M5.861998295141533 0 C5.861998295141533 5.346398526020947, 5.861998295141533 10.692797052041893, 5.861998295141533 13.677996021996911 M5.861998295141533 0 C5.861998295141533 4.496599266354498, 5.861998295141533 8.993198532708996, 5.861998295141533 13.677996021996911 M5.861998295141533 13.677996021996911 C3.891777796747413 13.677996021996911, 1.9215572983532936 13.677996021996911, 0 13.677996021996911 M5.861998295141533 13.677996021996911 C4.038711915432156 13.677996021996911, 2.2154255357227792 13.677996021996911, 0 13.677996021996911 M0 13.677996021996911 C0 10.407330957556045, 0 7.13666589311518, 0 0 M0 13.677996021996911 C0 8.615481990624176, 0 3.5529679592514416, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(563.5290425017101 296.5639659801868) rotate(0 2.9309991475707875 6.838998010998466)"><path d="M0 0 L5.861998295141533 0 L5.861998295141533 13.677996021996911 L0 13.677996021996911" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C1.992445036968253 0, 3.984890073936506 0, 5.861998295141533 0 M0 0 C2.1991607886562967 0, 4.398321577312593 0, 5.861998295141533 0 M5.861998295141533 0 C5.861998295141533 3.9068180477119214, 5.861998295141533 7.813636095423843, 5.861998295141533 13.677996021996911 M5.861998295141533 0 C5.861998295141533 4.436560428108088, 5.861998295141533 8.873120856216175, 5.861998295141533 13.677996021996911 M5.861998295141533 13.677996021996911 C4.2584782283409455 13.677996021996911, 2.6549581615403572 13.677996021996911, 0 13.677996021996911 M5.861998295141533 13.677996021996911 C3.951389670446835 13.677996021996911, 2.040781045752137 13.677996021996911, 0 13.677996021996911 M0 13.677996021996911 C0 9.992197423731628, 0 6.306398825466346, 0 0 M0 13.677996021996911 C0 9.18606117187456, 0 4.694126321752208, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(557.2990807517933 312.9973019438262) rotate(0 0.24424992896422282 12.945246235104264)"><path d="M0 0 C0.13958349564106426 7.397925268976406, 0.2791669912821285 14.795850537952813, 0.4884998579284611 25.89049247020844 M0 0 C0.12864824285337711 6.818356871228986, 0.25729648570675423 13.636713742457973, 0.4884998579284611 25.89049247020844" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(548.2098876999967 311.88889893997066) rotate(0 0.24424992896422282 13.677996021996933)"><path d="M0 0 C0.13230184343367635 7.408903232285875, 0.2646036868673527 14.81780646457175, 0.4884998579284611 27.355992043993822 M0 0 C0.10380505322458383 5.813082980576695, 0.20761010644916766 11.62616596115339, 0.4884998579284611 27.355992043993822" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(567.129978871211 313.0186100862052) rotate(0 0.7327497868926685 12.456746377175818)"><path d="M0 0 C0.45543009671823337 7.742311644209971, 0.9108601934364667 15.484623288419941, 1.4654995737853833 24.913492754351527 M0 0 C0.4866783450781988 8.273531866329382, 0.9733566901563976 16.547063732658764, 1.4654995737853833 24.913492754351527" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(575.7498470395947 321.1805929153993) rotate(0 -16.60899516956772 0)"><path d="M0 0 C-7.793431841498607 0, -15.586863682997214 0, -33.21799033913535 0 M0 0 C-10.464785813465676 0, -20.929571626931352 0, -33.21799033913535 0" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(575.2745570852853 329.8761658787048) rotate(0 -17.58599488542461 0.48849985792844564)"><path d="M0 0 C-8.922130076295742 0.2478369465637708, -17.844260152591485 0.4956738931275416, -35.17198977084917 0.9769997158569222 M0 0 C-12.974155529517464 0.36039320915326317, -25.94831105903493 0.7207864183065263, -35.17198977084917 0.9769997158569222" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(18.929579257965088 10) rotate(0 316 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"># all values (except auto refund) load default and are optional overriden</text></g><g transform="translate(122.83358089511557 657.9878683353941) rotate(0 66 13.5)"><text x="0" y="21" font-family="Helvetica, Segoe UI Emoji" font-size="23.49480968858131px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">fullfilment url</text></g><g transform="translate(381.460536751943 650.9394254288181) rotate(0 99.85294117647061 18.79584775086505)"><path d="M0 0 C48.22669300393149 0, 96.45338600786297 0, 199.70588235294125 0 M0 0 C45.50370675193915 0, 91.0074135038783 0, 199.70588235294125 0 M199.70588235294125 0 C199.70588235294125 8.990837124474735, 199.70588235294125 17.98167424894947, 199.70588235294125 37.59169550173011 M199.70588235294125 0 C199.70588235294125 14.383608090506296, 199.70588235294125 28.767216181012593, 199.70588235294125 37.59169550173011 M199.70588235294125 37.59169550173011 C152.58380565441712 37.59169550173011, 105.46172895589298 37.59169550173011, 0 37.59169550173011 M199.70588235294125 37.59169550173011 C158.28431744917356 37.59169550173011, 116.86275254540587 37.59169550173011, 0 37.59169550173011 M0 37.59169550173011 C0 26.598232012306532, 0 15.604768522882956, 0 0 M0 37.59169550173011 C0 26.77625049695012, 0 15.960805492170131, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(124.43070263151071 362.6087328723743) rotate(0 66.5 13.5)"><text x="0" y="21" font-family="Helvetica, Segoe UI Emoji" font-size="23.494809688581316px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">delivery date</text></g><g transform="translate(387.78648718559225 361.87284353785617) rotate(0 69.75578583521315 18.03461720393034)"><path d="M0 0 L139.51157167042618 0 L139.51157167042618 36.06923440786065 L0 36.06923440786065" stroke="none" stroke-width="0" fill="#fff"></path><path d="M0 0 C55.43980877578232 0, 110.87961755156464 0, 139.51157167042618 0 M0 0 C38.67123892787831 0, 77.34247785575663 0, 139.51157167042618 0 M139.51157167042618 0 C139.51157167042618 12.794862940982673, 139.51157167042618 25.589725881965347, 139.51157167042618 36.06923440786065 M139.51157167042618 0 C139.51157167042618 12.89935412691385, 139.51157167042618 25.7987082538277, 139.51157167042618 36.06923440786065 M139.51157167042618 36.06923440786065 C88.24394089405709 36.06923440786065, 36.97631011768799 36.06923440786065, 0 36.06923440786065 M139.51157167042618 36.06923440786065 C84.87579098476786 36.06923440786065, 30.240010299109528 36.06923440786065, 0 36.06923440786065 M0 36.06923440786065 C0 24.201030776872482, 0 12.332827145884316, 0 0 M0 36.06923440786065 C0 25.001084232279638, 0 13.932934056698628, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(421.6375334630645 368.1834641515052) rotate(0 4.884998579284627 12.212496448211482)"><text x="0" y="17.42499289642305" font-family="Virgil, Segoe UI Emoji" font-size="19.539994317138444px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(451.4360247967006 367.6949642935774) rotate(0 4.884998579284627 12.212496448211482)"><text x="0" y="17.42499289642305" font-family="Virgil, Segoe UI Emoji" font-size="19.539994317138444px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(538.3889995079655 360.8559662825792) rotate(0 17.34174495646039 17.34174495646039)"><path d="M0 0 L34.68348991292074 0 L34.68348991292074 34.68348991292074 L0 34.68348991292074" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C9.57520347866013 0, 19.15040695732026 0, 34.68348991292074 0 M0 0 C12.829012201846544 0, 25.658024403693087 0, 34.68348991292074 0 M34.68348991292074 0 C34.68348991292074 13.387734282680508, 34.68348991292074 26.775468565361017, 34.68348991292074 34.68348991292074 M34.68348991292074 0 C34.68348991292074 7.41516960577264, 34.68348991292074 14.83033921154528, 34.68348991292074 34.68348991292074 M34.68348991292074 34.68348991292074 C27.256849805847033 34.68348991292074, 19.83020969877332 34.68348991292074, 0 34.68348991292074 M34.68348991292074 34.68348991292074 C20.983841327597055 34.68348991292074, 7.2841927422733725 34.68348991292074, 0 34.68348991292074 M0 34.68348991292074 C0 23.17218993515759, 0 11.660889957394435, 0 0 M0 34.68348991292074 C0 26.586830031075714, 0 18.490170149230686, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(539.3659992238224 361.83296599843425) rotate(0 17.097495027496166 4.396498721356124)"><path d="M0 0 L34.19499005499228 0 L34.19499005499228 8.792997442712293 L0 8.792997442712293" stroke="none" stroke-width="0" fill="#000"></path><path d="M0 0 C12.285038274544192 0, 24.570076549088384 0, 34.19499005499228 0 M0 0 C9.276475028002112 0, 18.552950056004224 0, 34.19499005499228 0 M34.19499005499228 0 C34.19499005499228 2.434006584223475, 34.19499005499228 4.86801316844695, 34.19499005499228 8.792997442712293 M34.19499005499228 0 C34.19499005499228 2.781845972529476, 34.19499005499228 5.563691945058952, 34.19499005499228 8.792997442712293 M34.19499005499228 8.792997442712293 C24.602459615257793 8.792997442712293, 15.009929175523308 8.792997442712293, 0 8.792997442712293 M34.19499005499228 8.792997442712293 C21.001977236583443 8.792997442712293, 7.808964418174604 8.792997442712293, 0 8.792997442712293 M0 8.792997442712293 C0 5.841320005988653, 0 2.8896425692650114, 0 0 M0 8.792997442712293 C0 5.403896656500538, 0 2.0147958702887827, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(546.6934970927516 353.52846841364953) rotate(0 2.9309991475707875 6.838998010998466)"><path d="M0 0 L5.861998295141533 0 L5.861998295141533 13.677996021996911 L0 13.677996021996911" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C1.4406882612954708 0, 2.8813765225909416 0, 5.861998295141533 0 M0 0 C1.4006236417656008 0, 2.8012472835312017 0, 5.861998295141533 0 M5.861998295141533 0 C5.861998295141533 5.3156390105338645, 5.861998295141533 10.631278021067729, 5.861998295141533 13.677996021996911 M5.861998295141533 0 C5.861998295141533 4.455722168129303, 5.861998295141533 8.911444336258606, 5.861998295141533 13.677996021996911 M5.861998295141533 13.677996021996911 C3.5450520464645443 13.677996021996911, 1.2281057977875554 13.677996021996911, 0 13.677996021996911 M5.861998295141533 13.677996021996911 C3.64303247747399 13.677996021996911, 1.4240666598064466 13.677996021996911, 0 13.677996021996911 M0 13.677996021996911 C0 10.243041026991754, 0 6.808086031986596, 0 0 M0 13.677996021996911 C0 8.505417493634637, 0 3.3328389652723622, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(561.348492830605 353.52846841364953) rotate(0 2.9309991475707875 6.838998010998466)"><path d="M0 0 L5.861998295141533 0 L5.861998295141533 13.677996021996911 L0 13.677996021996911" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C1.4048860706216215 0, 2.809772141243243 0, 5.861998295141533 0 M0 0 C1.9050741409846754 0, 3.810148281969351 0, 5.861998295141533 0 M5.861998295141533 0 C5.861998295141533 2.947701635698273, 5.861998295141533 5.895403271396546, 5.861998295141533 13.677996021996911 M5.861998295141533 0 C5.861998295141533 3.884129481375102, 5.861998295141533 7.768258962750204, 5.861998295141533 13.677996021996911 M5.861998295141533 13.677996021996911 C4.442701754505925 13.677996021996911, 3.0234052138703165 13.677996021996911, 0 13.677996021996911 M5.861998295141533 13.677996021996911 C4.595862491244022 13.677996021996911, 3.32972668734651 13.677996021996911, 0 13.677996021996911 M0 13.677996021996911 C0 9.63321077458749, 0 5.588425527178066, 0 0 M0 13.677996021996911 C0 9.014838182708136, 0 4.3516803434193605, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(555.118531080688 369.9618043772889) rotate(0 0.24424992896422282 12.945246235104264)"><path d="M0 0 C0.10953645508111119 5.805432119298893, 0.21907291016222238 11.610864238597786, 0.4884998579284611 25.89049247020844 M0 0 C0.12451699391601756 6.599400677548931, 0.24903398783203512 13.198801355097862, 0.4884998579284611 25.89049247020844" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(546.0293380288911 368.85340137343337) rotate(0 0.24424992896422282 13.677996021996933)"><path d="M0 0 C0.10716094582593776 6.001012966252514, 0.2143218916518755 12.002025932505028, 0.4884998579284611 27.355992043993822 M0 0 C0.15526133988273694 8.694635033433268, 0.3105226797654739 17.389270066866537, 0.4884998579284611 27.355992043993822" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(564.9494292001057 369.9831125196679) rotate(0 0.7327497868926685 12.456746377175818)"><path d="M0 0 C0.41616099285571023 7.074736878547077, 0.8323219857114205 14.149473757094153, 1.4654995737853833 24.913492754351527 M0 0 C0.45905133818462057 7.803872749138553, 0.9181026763692411 15.607745498277106, 1.4654995737853833 24.913492754351527" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(573.5692973684893 378.145095348862) rotate(0 -16.60899516956772 0)"><path d="M0 0 C-7.2177111304083565 0, -14.435422260816713 0, -33.21799033913535 0 M0 0 C-11.641370495996155 0, -23.28274099199231 0, -33.21799033913535 0" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(573.0940074141797 386.8406683121675) rotate(0 -17.58599488542461 0.48849985792844564)"><path d="M0 0 C-9.749330494322896 0.270814735953414, -19.498660988645792 0.541629471906828, -35.17198977084917 0.9769997158569222 M0 0 C-12.476582768321407 0.3465717435644838, -24.953165536642814 0.6931434871289676, -35.17198977084917 0.9769997158569222" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(124.43146930138187 430.1561042809583) rotate(0 71 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="19.825388200978065px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">delivery location</text></g><g transform="translate(638.9002931167688 425.1997572307075) rotate(0 30.233717006491474 18.33848408590461)"><path d="M0 0 C22.472148607424298 0, 44.944297214848596 0, 60.46743401298301 0 M0 0 C17.41463295067124 0, 34.82926590134248 0, 60.46743401298301 0 M60.46743401298301 0 C60.46743401298301 11.592106789816704, 60.46743401298301 23.184213579633408, 60.46743401298301 36.676968171809314 M60.46743401298301 0 C60.46743401298301 9.014323088289395, 60.46743401298301 18.02864617657879, 60.46743401298301 36.676968171809314 M60.46743401298301 36.676968171809314 C39.47376126896 36.676968171809314, 18.48008852493698 36.676968171809314, 0 36.676968171809314 M60.46743401298301 36.676968171809314 C43.95284995083415 36.676968171809314, 27.438265888685287 36.676968171809314, 0 36.676968171809314 M0 36.676968171809314 C0 26.68601243134865, 0 16.69505669088799, 0 0 M0 36.676968171809314 C0 22.77452447295343, 0 8.872080774097551, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(666.6558365981346 431.1473736909927) rotate(0 0 10.903963510537892)"><path d="M0 0 C0 3.634654503512637, 0 18.173272517563184, 0 21.807927021075823 M0 0 C0 3.634654503512637, 0 18.173272517563184, 0 21.807927021075823" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(666.6558365981346 431.1473736909927) rotate(0 0 10.903963510537892)"><path d="M-3.729375162692038 11.561552972904538 C-2.761486101766064 14.220806312335792, -1.7935970408400899 16.880059651767045, 0 21.807927021075823 M-3.729375162692038 11.561552972904538 C-2.7688984867987685 14.200440951834132, -1.8084218109054992 16.839328930763727, 0 21.807927021075823" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(666.6558365981346 431.1473736909927) rotate(0 0 10.903963510537892)"><path d="M3.729375162692038 11.561552972904538 C2.761486101766064 14.220806312335792, 1.7935970408400899 16.880059651767045, 0 21.807927021075823 M3.729375162692038 11.561552972904538 C2.7688984867987685 14.200440951834132, 1.8084218109054992 16.839328930763727, 0 21.807927021075823" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(102 423.93245619264553) rotate(0 299.5 19)"><path d="M0 0 C193.9767573282123 0, 387.9535146564246 0, 599.0000000000001 0 M0 0 C162.25038655549292 0, 324.50077311098585 0, 599.0000000000001 0 M599.0000000000001 0 C599.0000000000001 10.080071184039117, 599.0000000000001 20.160142368078233, 599.0000000000001 38 M599.0000000000001 0 C599.0000000000001 14.464655616879465, 599.0000000000001 28.92931123375893, 599.0000000000001 38 M599.0000000000001 38 C364.0274778440595 38, 129.05495568811892 38, 0 38 M599.0000000000001 38 C396.98877884596595 38, 194.97755769193174 38, 0 38 M0 38 C0 27.496936300396918, 0 16.99387260079384, 0 0 M0 38 C0 25.07144419848919, 0 12.142888396978378, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g></svg> \ No newline at end of file
+ <rect x="0" y="0" width="812" height="755.4705463593664" fill="#ffffff"></rect><g transform="translate(10 57.28872817754791) rotate(0 396 344.09090909090924)"><path d="M0 0 C163.13469960540533 0, 326.26939921081066 0, 792 0 M0 0 C197.6944362178445 0, 395.388872435689 0, 792 0 M792 0 C792 158.56476755186247, 792 317.12953510372495, 792 688.1818181818186 M792 0 C792 266.1385155277837, 792 532.2770310555674, 792 688.1818181818186 M792 688.1818181818186 C541.9932290330529 688.1818181818186, 291.9864580661058 688.1818181818186, 0 688.1818181818186 M792 688.1818181818186 C500.6049041256308 688.1818181818186, 209.20980825126162 688.1818181818186, 0 688.1818181818186 M0 688.1818181818186 C0 513.5637151258577, 0 338.94561206989687, 0 0 M0 688.1818181818186 C0 501.1274236320436, 0 314.07302908226865, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(49 89.78872817754723) rotate(0 355.94636678200686 308.9999999999999)"><path d="M0 0 C196.37916639762955 0, 392.7583327952591 0, 711.8927335640136 0 M0 0 C222.65387708782745 0, 445.3077541756549 0, 711.8927335640136 0 M711.8927335640136 0 C711.8927335640136 136.01048013232645, 711.8927335640136 272.0209602646529, 711.8927335640136 617.9999999999998 M711.8927335640136 0 C711.8927335640136 229.1515129242092, 711.8927335640136 458.3030258484184, 711.8927335640136 617.9999999999998 M711.8927335640136 617.9999999999998 C540.7157390920328 617.9999999999998, 369.5387446200519 617.9999999999998, 0 617.9999999999998 M711.8927335640136 617.9999999999998 C560.9805535182735 617.9999999999998, 410.06837347253344 617.9999999999998, 0 617.9999999999998 M0 617.9999999999998 C0 487.54947386719266, 0 357.0989477343856, 0 0 M0 617.9999999999998 C0 469.64537168405934, 0 321.29074336811885, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(49 134.42886658585485) rotate(0 355.35899653979254 0)"><path d="M0 0 C118.45299884659751 0, 592.2649942329875 0, 710.7179930795851 0 M0 0 C118.45299884659751 0, 592.2649942329875 0, 710.7179930795851 0" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(77.19377162629803 96.83717108412088) rotate(0 45.22750865051904 13.50951557093424)"><text x="0" y="21.01903114186851" font-family="Helvetica, Segoe UI Emoji" font-size="23.494809688581313px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">payment</text></g><g transform="translate(686.884083044984 90.96346866197814) rotate(0 35.82958477508646 21.732698961937672)"><path d="M0 0 C25.693898552344557 0, 51.38779710468911 0, 71.65916955017302 0 M0 0 C18.423871399928533 0, 36.847742799857066 0, 71.65916955017302 0 M71.65916955017302 0 C71.65916955017302 14.811010985339712, 71.65916955017302 29.622021970679423, 71.65916955017302 43.46539792387543 M71.65916955017302 0 C71.65916955017302 9.170037636031626, 71.65916955017302 18.340075272063252, 71.65916955017302 43.46539792387543 M71.65916955017302 43.46539792387543 C48.850217413141436 43.46539792387543, 26.041265276109854 43.46539792387543, 0 43.46539792387543 M71.65916955017302 43.46539792387543 C50.35093945471351 43.46539792387543, 29.042709359254005 43.46539792387543, 0 43.46539792387543 M0 43.46539792387543 C0 27.43454704114484, 0 11.403696158414249, 0 0 M0 43.46539792387543 C0 26.72246210199255, 0 9.979526280109674, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(719.7768166089982 98.01191156855225) rotate(0 0 12.922145328719694)"><path d="M0 0 C0 4.307381776239908, 0 21.53690888119954, 0 25.844290657439448 M0 0 C0 4.307381776239908, 0 21.53690888119954, 0 25.844290657439448" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(719.7768166089982 98.01191156855225) rotate(0 0 12.922145328719694)"><path d="M-4.4196339974038406 13.701446047318425 C-3.1323002724435964 17.238366387949103, -1.8449665474833528 20.77528672857978, 0 25.844290657439448 M-4.4196339974038406 13.701446047318425 C-2.8705976157310924 17.957388527877995, -1.3215612340583442 22.213331008437564, 0 25.844290657439448" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(719.7768166089982 98.01191156855225) rotate(0 0 12.922145328719694)"><path d="M4.4196339974038406 13.701446047318425 C3.1323002724435964 17.238366387949103, 1.8449665474833528 20.77528672857978, 0 25.844290657439448 M4.4196339974038406 13.701446047318425 C2.8705976157310924 17.957388527877995, 1.3215612340583442 22.213331008437564, 0 25.844290657439448" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(122.41700882982559 491.89835384599746) rotate(0 41.70328719723187 13.50951557093424)"><text x="0" y="21.01903114186851" font-family="Helvetica, Segoe UI Emoji" font-size="23.494809688581313px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">max fee</text></g><g transform="translate(381.043964686653 486.02465142385245) rotate(0 99.85294117647061 18.79584775086505)"><path d="M0 0 C44.61811129907696 0, 89.23622259815392 0, 199.70588235294125 0 M0 0 C79.29353130055485 0, 158.5870626011097 0, 199.70588235294125 0 M199.70588235294125 0 C199.70588235294125 8.759946174821641, 199.70588235294125 17.519892349643282, 199.70588235294125 37.59169550173011 M199.70588235294125 0 C199.70588235294125 10.044274510345245, 199.70588235294125 20.08854902069049, 199.70588235294125 37.59169550173011 M199.70588235294125 37.59169550173011 C120.15937504977649 37.59169550173011, 40.61286774661173 37.59169550173011, 0 37.59169550173011 M199.70588235294125 37.59169550173011 C131.51639080907717 37.59169550173011, 63.32689926521306 37.59169550173011, 0 37.59169550173011 M0 37.59169550173011 C0 22.898467848158624, 0 8.205240194587144, 0 0 M0 37.59169550173011 C0 24.276735533449063, 0 10.961775565168022, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(122.41700882982559 548.2858970985903) rotate(0 66.37283737024222 13.50951557093424)"><text x="0" y="21.01903114186851" font-family="Helvetica, Segoe UI Emoji" font-size="23.49480968858131px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">max wire fee</text></g><g transform="translate(381.043964686653 537.7132327387317) rotate(0 99.85294117647061 18.79584775086505)"><path d="M0 0 C73.07786602499513 0, 146.15573204999026 0, 199.70588235294125 0 M0 0 C66.5611449872856 0, 133.1222899745712 0, 199.70588235294125 0 M199.70588235294125 0 C199.70588235294125 11.502282709924822, 199.70588235294125 23.004565419849644, 199.70588235294125 37.59169550173011 M199.70588235294125 0 C199.70588235294125 11.270341817534508, 199.70588235294125 22.540683635069016, 199.70588235294125 37.59169550173011 M199.70588235294125 37.59169550173011 C129.25950294366 37.59169550173011, 58.813123534378775 37.59169550173011, 0 37.59169550173011 M199.70588235294125 37.59169550173011 C136.2727813783705 37.59169550173011, 72.83968040379972 37.59169550173011, 0 37.59169550173011 M0 37.59169550173011 C0 24.7357254136908, 0 11.879755325651498, 0 0 M0 37.59169550173011 C0 25.50134813334909, 0 13.411000764968072, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(122.41700882982559 608.1976618044737) rotate(0 108.66349480968859 13.50951557093424)"><text x="0" y="21.01903114186851" font-family="Helvetica, Segoe UI Emoji" font-size="23.49480968858131px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">wire fee amortization</text></g><g transform="translate(381.043964686653 601.1492188978978) rotate(0 99.85294117647061 18.79584775086505)"><path d="M0 0 C63.18052968749888 0, 126.36105937499777 0, 199.70588235294125 0 M0 0 C58.832443530780886 0, 117.66488706156177 0, 199.70588235294125 0 M199.70588235294125 0 C199.70588235294125 12.2283371196383, 199.70588235294125 24.4566742392766, 199.70588235294125 37.59169550173011 M199.70588235294125 0 C199.70588235294125 13.842964280734428, 199.70588235294125 27.685928561468856, 199.70588235294125 37.59169550173011 M199.70588235294125 37.59169550173011 C137.16080129305453 37.59169550173011, 74.61572023316782 37.59169550173011, 0 37.59169550173011 M199.70588235294125 37.59169550173011 C124.86287547313776 37.59169550173011, 50.01986859333428 37.59169550173011, 0 37.59169550173011 M0 37.59169550173011 C0 25.7131450870561, 0 13.834594672382085, 0 0 M0 37.59169550173011 C0 29.765293690768495, 0 21.93889187980688, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(126.6112523026161 170.85274201837865) rotate(0 81.05709342560556 13.50951557093424)"><text x="0" y="21.01903114186851" font-family="Helvetica, Segoe UI Emoji" font-size="23.494809688581313px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">refund deadline</text></g><g transform="translate(389.96703685669763 170.11685268386054) rotate(0 69.75578583521315 18.03461720393034)"><path d="M0 0 L139.51157167042618 0 L139.51157167042618 36.06923440786065 L0 36.06923440786065" stroke="none" stroke-width="0" fill="#fff"></path><path d="M0 0 C38.588792372791914 0, 77.17758474558383 0, 139.51157167042618 0 M0 0 C51.270889713540704 0, 102.54177942708141 0, 139.51157167042618 0 M139.51157167042618 0 C139.51157167042618 11.195579849357195, 139.51157167042618 22.39115969871439, 139.51157167042618 36.06923440786065 M139.51157167042618 0 C139.51157167042618 7.478536088246398, 139.51157167042618 14.957072176492796, 139.51157167042618 36.06923440786065 M139.51157167042618 36.06923440786065 C106.073634546001 36.06923440786065, 72.63569742157583 36.06923440786065, 0 36.06923440786065 M139.51157167042618 36.06923440786065 C90.59517821844433 36.06923440786065, 41.678784766462485 36.06923440786065, 0 36.06923440786065 M0 36.06923440786065 C0 28.587188228147372, 0 21.105142048434097, 0 0 M0 36.06923440786065 C0 24.459576137678855, 0 12.849917867497062, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(423.8180831341699 176.4274732975059) rotate(0 4.884998579284627 12.212496448211482)"><text x="0" y="17.42499289642305" font-family="Virgil, Segoe UI Emoji" font-size="19.539994317138444px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(453.616574467806 175.93897343957906) rotate(0 4.884998579284627 12.212496448211482)"><text x="0" y="17.42499289642305" font-family="Virgil, Segoe UI Emoji" font-size="19.539994317138444px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(540.5695491790709 169.09997542858218) rotate(0 17.34174495646039 17.34174495646039)"><path d="M0 0 L34.68348991292074 0 L34.68348991292074 34.68348991292074 L0 34.68348991292074" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C12.350741138777865 0, 24.70148227755573 0, 34.68348991292074 0 M0 0 C13.090885427004103 0, 26.181770854008207 0, 34.68348991292074 0 M34.68348991292074 0 C34.68348991292074 8.759752021302454, 34.68348991292074 17.519504042604908, 34.68348991292074 34.68348991292074 M34.68348991292074 0 C34.68348991292074 12.827119610736222, 34.68348991292074 25.654239221472444, 34.68348991292074 34.68348991292074 M34.68348991292074 34.68348991292074 C26.26168783725121 34.68348991292074, 17.83988576158168 34.68348991292074, 0 34.68348991292074 M34.68348991292074 34.68348991292074 C25.047276653082115 34.68348991292074, 15.411063393243492 34.68348991292074, 0 34.68348991292074 M0 34.68348991292074 C0 21.65963125803831, 0 8.635772603155882, 0 0 M0 34.68348991292074 C0 22.816433409973676, 0 10.949376907026608, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(541.5465488949278 170.07697514443726) rotate(0 17.097495027496166 4.396498721356124)"><path d="M0 0 L34.19499005499228 0 L34.19499005499228 8.792997442712293 L0 8.792997442712293" stroke="none" stroke-width="0" fill="#000"></path><path d="M0 0 C8.416124992044198 0, 16.832249984088396 0, 34.19499005499228 0 M0 0 C12.612778286946597 0, 25.225556573893194 0, 34.19499005499228 0 M34.19499005499228 0 C34.19499005499228 2.784839725361176, 34.19499005499228 5.569679450722352, 34.19499005499228 8.792997442712293 M34.19499005499228 0 C34.19499005499228 2.6248021666892867, 34.19499005499228 5.249604333378573, 34.19499005499228 8.792997442712293 M34.19499005499228 8.792997442712293 C22.07788480659337 8.792997442712293, 9.96077955819446 8.792997442712293, 0 8.792997442712293 M34.19499005499228 8.792997442712293 C25.609229118108246 8.792997442712293, 17.023468181224214 8.792997442712293, 0 8.792997442712293 M0 8.792997442712293 C0 5.374793220870361, 0 1.956588999028427, 0 0 M0 8.792997442712293 C0 6.7982943981253765, 0 4.80359135353846, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(548.874046763857 161.77247755965436) rotate(0 2.9309991475707875 6.838998010998466)"><path d="M0 0 L5.861998295141533 0 L5.861998295141533 13.677996021996911 L0 13.677996021996911" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C2.06572777238916 0, 4.13145554477832 0, 5.861998295141533 0 M0 0 C1.6284420677636307 0, 3.2568841355272613 0, 5.861998295141533 0 M5.861998295141533 0 C5.861998295141533 4.0886379104374235, 5.861998295141533 8.177275820874847, 5.861998295141533 13.677996021996911 M5.861998295141533 0 C5.861998295141533 4.405838529784974, 5.861998295141533 8.811677059569949, 5.861998295141533 13.677996021996911 M5.861998295141533 13.677996021996911 C3.787286061220638 13.677996021996911, 1.7125738272997424 13.677996021996911, 0 13.677996021996911 M5.861998295141533 13.677996021996911 C4.3944272776554225 13.677996021996911, 2.9268562601693118 13.677996021996911, 0 13.677996021996911 M0 13.677996021996911 C0 9.10398929446179, 0 4.52998256692667, 0 0 M0 13.677996021996911 C0 9.353978362633276, 0 5.029960703269641, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(563.5290425017101 161.77247755965436) rotate(0 2.9309991475707875 6.838998010998466)"><path d="M0 0 L5.861998295141533 0 L5.861998295141533 13.677996021996911 L0 13.677996021996911" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C1.9136207457158667 0, 3.8272414914317334 0, 5.861998295141533 0 M0 0 C1.7752901701469925 0, 3.550580340293985 0, 5.861998295141533 0 M5.861998295141533 0 C5.861998295141533 3.1488935786452767, 5.861998295141533 6.2977871572905535, 5.861998295141533 13.677996021996911 M5.861998295141533 0 C5.861998295141533 4.449927547836239, 5.861998295141533 8.899855095672478, 5.861998295141533 13.677996021996911 M5.861998295141533 13.677996021996911 C4.27455321609603 13.677996021996911, 2.6871081370505263 13.677996021996911, 0 13.677996021996911 M5.861998295141533 13.677996021996911 C3.940863191629518 13.677996021996911, 2.019728088117503 13.677996021996911, 0 13.677996021996911 M0 13.677996021996911 C0 10.13870173751964, 0 6.599407453042369, 0 0 M0 13.677996021996911 C0 9.428222501847815, 0 5.178448981698718, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(557.2990807517933 178.205813523291) rotate(0 0.24424992896422282 12.945246235104264)"><path d="M0 0 C0.13838525821577435 7.334418685436041, 0.2767705164315487 14.668837370872081, 0.4884998579284611 25.89049247020844 M0 0 C0.18365905060197285 9.733929681904561, 0.3673181012039457 19.467859363809122, 0.4884998579284611 25.89049247020844" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(548.2098876999967 177.0974105194373) rotate(0 0.24424992896422282 13.677996021996933)"><path d="M0 0 C0.18081889830845407 10.125858305273429, 0.36163779661690815 20.251716610546858, 0.4884998579284611 27.355992043993822 M0 0 C0.1435033739142469 8.036188939197826, 0.2870067478284938 16.072377878395653, 0.4884998579284611 27.355992043993822" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(567.129978871211 178.22712166566998) rotate(0 0.7327497868926685 12.456746377175818)"><path d="M0 0 C0.49131225684945856 8.352308366440798, 0.9826245136989171 16.704616732881597, 1.4654995737853833 24.913492754351527 M0 0 C0.3645462207600854 6.197285752921455, 0.7290924415201708 12.39457150584291, 1.4654995737853833 24.913492754351527" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(575.7498470395947 186.38910449486139) rotate(0 -16.60899516956772 0)"><path d="M0 0 C-9.850046834715748 0, -19.700093669431496 0, -33.21799033913535 0 M0 0 C-11.978115758822755 0, -23.95623151764551 0, -33.21799033913535 0" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(575.2745570852853 195.08467745817006) rotate(0 -17.58599488542461 0.48849985792844564)"><path d="M0 0 C-10.91708283817915 0.3032523010605322, -21.8341656763583 0.6065046021210644, -35.17198977084917 0.9769997158569222 M0 0 C-7.292502852220365 0.20256952367278808, -14.58500570444073 0.40513904734557615, -35.17198977084917 0.9769997158569222" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(126.6112523026161 236.4338141678163) rotate(0 66.37283737024222 13.50951557093424)"><text x="0" y="21.01903114186851" font-family="Helvetica, Segoe UI Emoji" font-size="23.49480968858131px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">pay deadline</text></g><g transform="translate(389.96703685669763 235.69792483329775) rotate(0 69.75578583521315 18.03461720393034)"><path d="M0 0 L139.51157167042618 0 L139.51157167042618 36.06923440786065 L0 36.06923440786065" stroke="none" stroke-width="0" fill="#fff"></path><path d="M0 0 C47.50166837735665 0, 95.0033367547133 0, 139.51157167042618 0 M0 0 C49.76376503488774 0, 99.52753006977548 0, 139.51157167042618 0 M139.51157167042618 0 C139.51157167042618 8.446743562554808, 139.51157167042618 16.893487125109615, 139.51157167042618 36.06923440786065 M139.51157167042618 0 C139.51157167042618 11.47235701590513, 139.51157167042618 22.94471403181026, 139.51157167042618 36.06923440786065 M139.51157167042618 36.06923440786065 C96.27412265275322 36.06923440786065, 53.03667363508026 36.06923440786065, 0 36.06923440786065 M139.51157167042618 36.06923440786065 C94.95422630662594 36.06923440786065, 50.39688094282572 36.06923440786065, 0 36.06923440786065 M0 36.06923440786065 C0 26.300498294737366, 0 16.531762181614084, 0 0 M0 36.06923440786065 C0 28.404608233033215, 0 20.739982058205783, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(423.8180831341699 242.00854544694494) rotate(0 4.884998579284627 12.212496448211482)"><text x="0" y="17.42499289642305" font-family="Virgil, Segoe UI Emoji" font-size="19.539994317138444px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(453.616574467806 241.52004558901763) rotate(0 4.884998579284627 12.212496448211482)"><text x="0" y="17.42499289642305" font-family="Virgil, Segoe UI Emoji" font-size="19.539994317138444px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(540.5695491790709 234.68104757801984) rotate(0 17.34174495646039 17.34174495646039)"><path d="M0 0 L34.68348991292074 0 L34.68348991292074 34.68348991292074 L0 34.68348991292074" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C10.984645583369092 0, 21.969291166738184 0, 34.68348991292074 0 M0 0 C10.353386324163305 0, 20.70677264832661 0, 34.68348991292074 0 M34.68348991292074 0 C34.68348991292074 12.290206751947466, 34.68348991292074 24.58041350389493, 34.68348991292074 34.68348991292074 M34.68348991292074 0 C34.68348991292074 8.708414664553807, 34.68348991292074 17.416829329107614, 34.68348991292074 34.68348991292074 M34.68348991292074 34.68348991292074 C21.200573260099773 34.68348991292074, 7.717656607278801 34.68348991292074, 0 34.68348991292074 M34.68348991292074 34.68348991292074 C26.81549457038345 34.68348991292074, 18.94749922784616 34.68348991292074, 0 34.68348991292074 M0 34.68348991292074 C0 25.885278309906877, 0 17.08706670689301, 0 0 M0 34.68348991292074 C0 21.8895309879799, 0 9.095572063039057, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(541.5465488949278 235.65804729387492) rotate(0 17.097495027496166 4.396498721356124)"><path d="M0 0 L34.19499005499228 0 L34.19499005499228 8.792997442712293 L0 8.792997442712293" stroke="none" stroke-width="0" fill="#000"></path><path d="M0 0 C10.22159477609356 0, 20.44318955218712 0, 34.19499005499228 0 M0 0 C11.014596324462437 0, 22.029192648924873 0, 34.19499005499228 0 M34.19499005499228 0 C34.19499005499228 3.1120683508813407, 34.19499005499228 6.224136701762681, 34.19499005499228 8.792997442712293 M34.19499005499228 0 C34.19499005499228 2.2013565262291643, 34.19499005499228 4.402713052458329, 34.19499005499228 8.792997442712293 M34.19499005499228 8.792997442712293 C22.75997323615448 8.792997442712293, 11.324956417316677 8.792997442712293, 0 8.792997442712293 M34.19499005499228 8.792997442712293 C23.38494590658319 8.792997442712293, 12.574901758174104 8.792997442712293, 0 8.792997442712293 M0 8.792997442712293 C0 5.889444189066426, 0 2.9858909354205574, 0 0 M0 8.792997442712293 C0 5.741208897211333, 0 2.689420351710372, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(548.874046763857 227.35354970909202) rotate(0 2.9309991475707875 6.838998010998466)"><path d="M0 0 L5.861998295141533 0 L5.861998295141533 13.677996021996911 L0 13.677996021996911" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C1.3495258194194044 0, 2.699051638838809 0, 5.861998295141533 0 M0 0 C1.907111806215531 0, 3.814223612431062 0, 5.861998295141533 0 M5.861998295141533 0 C5.861998295141533 3.7040385177728417, 5.861998295141533 7.408077035545683, 5.861998295141533 13.677996021996911 M5.861998295141533 0 C5.861998295141533 4.482648574861369, 5.861998295141533 8.965297149722739, 5.861998295141533 13.677996021996911 M5.861998295141533 13.677996021996911 C4.345157887508417 13.677996021996911, 2.828317479875301 13.677996021996911, 0 13.677996021996911 M5.861998295141533 13.677996021996911 C4.040666786506207 13.677996021996911, 2.2193352778708797 13.677996021996911, 0 13.677996021996911 M0 13.677996021996911 C0 8.942165936497862, 0 4.20633585099881, 0 0 M0 13.677996021996911 C0 9.845296872419517, 0 6.012597722842125, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(563.5290425017101 227.35354970909202) rotate(0 2.9309991475707875 6.838998010998466)"><path d="M0 0 L5.861998295141533 0 L5.861998295141533 13.677996021996911 L0 13.677996021996911" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C1.5320176410516326 0, 3.0640352821032653 0, 5.861998295141533 0 M0 0 C2.169100553518035 0, 4.33820110703607 0, 5.861998295141533 0 M5.861998295141533 0 C5.861998295141533 4.243283857466258, 5.861998295141533 8.486567714932516, 5.861998295141533 13.677996021996911 M5.861998295141533 0 C5.861998295141533 4.871870315718041, 5.861998295141533 9.743740631436083, 5.861998295141533 13.677996021996911 M5.861998295141533 13.677996021996911 C4.453460484325019 13.677996021996911, 3.0449226735085038 13.677996021996911, 0 13.677996021996911 M5.861998295141533 13.677996021996911 C3.658298036524886 13.677996021996911, 1.4545977779082389 13.677996021996911, 0 13.677996021996911 M0 13.677996021996911 C0 9.954515139904878, 0 6.231034257812844, 0 0 M0 13.677996021996911 C0 9.474895524801425, 0 5.27179502760594, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(557.2990807517933 243.78688567272866) rotate(0 0.24424992896422282 12.945246235104264)"><path d="M0 0 C0.1131082943342409 5.994739599714768, 0.2262165886684818 11.989479199429535, 0.4884998579284611 25.89049247020844 M0 0 C0.11061345453975935 5.862513090607246, 0.2212269090795187 11.725026181214492, 0.4884998579284611 25.89049247020844" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(548.2098876999967 242.6784826688745) rotate(0 0.24424992896422282 13.677996021996933)"><path d="M0 0 C0.11589865333866953 6.490324586965493, 0.23179730667733905 12.980649173930987, 0.4884998579284611 27.355992043993822 M0 0 C0.14872427158435972 8.328559208724144, 0.29744854316871944 16.657118417448288, 0.4884998579284611 27.355992043993822" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(567.129978871211 243.80819381510855) rotate(0 0.7327497868926685 12.456746377175818)"><path d="M0 0 C0.29443945475956246 5.005470730912564, 0.5888789095191249 10.010941461825128, 1.4654995737853833 24.913492754351527 M0 0 C0.5640236075493323 9.588401328338653, 1.1280472150986647 19.176802656677307, 1.4654995737853833 24.913492754351527" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(575.7498470395947 251.97017664429995) rotate(0 -16.60899516956772 0)"><path d="M0 0 C-7.961641167542139 0, -15.923282335084277 0, -33.21799033913535 0 M0 0 C-11.647093252965808 0, -23.294186505931616 0, -33.21799033913535 0" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(575.2745570852853 260.66574960760863) rotate(0 -17.58599488542461 0.48849985792844564)"><path d="M0 0 C-8.236625563486276 0.22879515454128563, -16.473251126972553 0.45759030908257126, -35.17198977084917 0.9769997158569222 M0 0 C-11.186975000584102 0.3107493055717809, -22.373950001168204 0.6214986111435618, -35.17198977084917 0.9769997158569222" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(126.6112523026161 305.64423043891156) rotate(0 106.90138408304506 13.50951557093424)"><text x="0" y="21.01903114186851" font-family="Helvetica, Segoe UI Emoji" font-size="23.494809688581316px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">auto refund deadline</text></g><g transform="translate(389.96703685669763 304.90834110439346) rotate(0 69.75578583521315 18.03461720393034)"><path d="M0 0 L139.51157167042618 0 L139.51157167042618 36.06923440786065 L0 36.06923440786065" stroke="none" stroke-width="0" fill="#fff"></path><path d="M0 0 C54.233956780562394 0, 108.46791356112479 0, 139.51157167042618 0 M0 0 C31.64838368021466 0, 63.29676736042932 0, 139.51157167042618 0 M139.51157167042618 0 C139.51157167042618 9.149735435384923, 139.51157167042618 18.299470870769845, 139.51157167042618 36.06923440786065 M139.51157167042618 0 C139.51157167042618 13.305128884862302, 139.51157167042618 26.610257769724605, 139.51157167042618 36.06923440786065 M139.51157167042618 36.06923440786065 C91.61872293837436 36.06923440786065, 43.72587420632256 36.06923440786065, 0 36.06923440786065 M139.51157167042618 36.06923440786065 C96.71713609249963 36.06923440786065, 53.922700514573094 36.06923440786065, 0 36.06923440786065 M0 36.06923440786065 C0 22.783353778422555, 0 9.497473148984461, 0 0 M0 36.06923440786065 C0 25.237278543595075, 0 14.405322679329501, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(423.8180831341699 311.21896171804246) rotate(0 4.884998579284627 12.212496448211482)"><text x="0" y="17.42499289642305" font-family="Virgil, Segoe UI Emoji" font-size="19.539994317138444px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(453.616574467806 310.7304618601147) rotate(0 4.884998579284627 12.212496448211482)"><text x="0" y="17.42499289642305" font-family="Virgil, Segoe UI Emoji" font-size="19.539994317138444px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(540.5695491790709 303.89146384911646) rotate(0 17.34174495646039 17.34174495646039)"><path d="M0 0 L34.68348991292074 0 L34.68348991292074 34.68348991292074 L0 34.68348991292074" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C8.333848713997714 0, 16.667697427995428 0, 34.68348991292074 0 M0 0 C13.03855986348183 0, 26.07711972696366 0, 34.68348991292074 0 M34.68348991292074 0 C34.68348991292074 9.4416836653048, 34.68348991292074 18.8833673306096, 34.68348991292074 34.68348991292074 M34.68348991292074 0 C34.68348991292074 10.65786197503141, 34.68348991292074 21.31572395006282, 34.68348991292074 34.68348991292074 M34.68348991292074 34.68348991292074 C21.040335615093984 34.68348991292074, 7.397181317267226 34.68348991292074, 0 34.68348991292074 M34.68348991292074 34.68348991292074 C27.450049553381234 34.68348991292074, 20.216609193841723 34.68348991292074, 0 34.68348991292074 M0 34.68348991292074 C0 23.797810389582665, 0 12.912130866244592, 0 0 M0 34.68348991292074 C0 25.594766385240447, 0 16.506042857560153, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(541.5465488949278 304.86846356497153) rotate(0 17.097495027496166 4.396498721356124)"><path d="M0 0 L34.19499005499228 0 L34.19499005499228 8.792997442712293 L0 8.792997442712293" stroke="none" stroke-width="0" fill="#000"></path><path d="M0 0 C12.256912387278875 0, 24.51382477455775 0, 34.19499005499228 0 M0 0 C9.337819074833758 0, 18.675638149667517 0, 34.19499005499228 0 M34.19499005499228 0 C34.19499005499228 2.953364940224322, 34.19499005499228 5.906729880448644, 34.19499005499228 8.792997442712293 M34.19499005499228 0 C34.19499005499228 1.8197494907887624, 34.19499005499228 3.6394989815775247, 34.19499005499228 8.792997442712293 M34.19499005499228 8.792997442712293 C24.437822160950887 8.792997442712293, 14.680654266909496 8.792997442712293, 0 8.792997442712293 M34.19499005499228 8.792997442712293 C26.745579617251906 8.792997442712293, 19.29616917951153 8.792997442712293, 0 8.792997442712293 M0 8.792997442712293 C0 5.897504324214696, 0 3.002011205717099, 0 0 M0 8.792997442712293 C0 6.010860718858778, 0 3.2287239950052617, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(548.874046763857 296.5639659801868) rotate(0 2.9309991475707875 6.838998010998466)"><path d="M0 0 L5.861998295141533 0 L5.861998295141533 13.677996021996911 L0 13.677996021996911" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C1.5383239337541497 0, 3.0766478675082993 0, 5.861998295141533 0 M0 0 C1.703193236340253 0, 3.406386472680506 0, 5.861998295141533 0 M5.861998295141533 0 C5.861998295141533 5.346398526020947, 5.861998295141533 10.692797052041893, 5.861998295141533 13.677996021996911 M5.861998295141533 0 C5.861998295141533 4.496599266354498, 5.861998295141533 8.993198532708996, 5.861998295141533 13.677996021996911 M5.861998295141533 13.677996021996911 C3.891777796747413 13.677996021996911, 1.9215572983532936 13.677996021996911, 0 13.677996021996911 M5.861998295141533 13.677996021996911 C4.038711915432156 13.677996021996911, 2.2154255357227792 13.677996021996911, 0 13.677996021996911 M0 13.677996021996911 C0 10.407330957556045, 0 7.13666589311518, 0 0 M0 13.677996021996911 C0 8.615481990624176, 0 3.5529679592514416, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(563.5290425017101 296.5639659801868) rotate(0 2.9309991475707875 6.838998010998466)"><path d="M0 0 L5.861998295141533 0 L5.861998295141533 13.677996021996911 L0 13.677996021996911" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C1.992445036968253 0, 3.984890073936506 0, 5.861998295141533 0 M0 0 C2.1991607886562967 0, 4.398321577312593 0, 5.861998295141533 0 M5.861998295141533 0 C5.861998295141533 3.9068180477119214, 5.861998295141533 7.813636095423843, 5.861998295141533 13.677996021996911 M5.861998295141533 0 C5.861998295141533 4.436560428108088, 5.861998295141533 8.873120856216175, 5.861998295141533 13.677996021996911 M5.861998295141533 13.677996021996911 C4.2584782283409455 13.677996021996911, 2.6549581615403572 13.677996021996911, 0 13.677996021996911 M5.861998295141533 13.677996021996911 C3.951389670446835 13.677996021996911, 2.040781045752137 13.677996021996911, 0 13.677996021996911 M0 13.677996021996911 C0 9.992197423731628, 0 6.306398825466346, 0 0 M0 13.677996021996911 C0 9.18606117187456, 0 4.694126321752208, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(557.2990807517933 312.9973019438262) rotate(0 0.24424992896422282 12.945246235104264)"><path d="M0 0 C0.13958349564106426 7.397925268976406, 0.2791669912821285 14.795850537952813, 0.4884998579284611 25.89049247020844 M0 0 C0.12864824285337711 6.818356871228986, 0.25729648570675423 13.636713742457973, 0.4884998579284611 25.89049247020844" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(548.2098876999967 311.88889893997066) rotate(0 0.24424992896422282 13.677996021996933)"><path d="M0 0 C0.13230184343367635 7.408903232285875, 0.2646036868673527 14.81780646457175, 0.4884998579284611 27.355992043993822 M0 0 C0.10380505322458383 5.813082980576695, 0.20761010644916766 11.62616596115339, 0.4884998579284611 27.355992043993822" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(567.129978871211 313.0186100862052) rotate(0 0.7327497868926685 12.456746377175818)"><path d="M0 0 C0.45543009671823337 7.742311644209971, 0.9108601934364667 15.484623288419941, 1.4654995737853833 24.913492754351527 M0 0 C0.4866783450781988 8.273531866329382, 0.9733566901563976 16.547063732658764, 1.4654995737853833 24.913492754351527" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(575.7498470395947 321.1805929153993) rotate(0 -16.60899516956772 0)"><path d="M0 0 C-7.793431841498607 0, -15.586863682997214 0, -33.21799033913535 0 M0 0 C-10.464785813465676 0, -20.929571626931352 0, -33.21799033913535 0" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(575.2745570852853 329.8761658787048) rotate(0 -17.58599488542461 0.48849985792844564)"><path d="M0 0 C-8.922130076295742 0.2478369465637708, -17.844260152591485 0.4956738931275416, -35.17198977084917 0.9769997158569222 M0 0 C-12.974155529517464 0.36039320915326317, -25.94831105903493 0.7207864183065263, -35.17198977084917 0.9769997158569222" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(18.929579257965088 10) rotate(0 316 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"># all values (except auto refund) load default and are optional overridden</text></g><g transform="translate(122.83358089511557 657.9878683353941) rotate(0 66 13.5)"><text x="0" y="21" font-family="Helvetica, Segoe UI Emoji" font-size="23.49480968858131px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">fullfilment url</text></g><g transform="translate(381.460536751943 650.9394254288181) rotate(0 99.85294117647061 18.79584775086505)"><path d="M0 0 C48.22669300393149 0, 96.45338600786297 0, 199.70588235294125 0 M0 0 C45.50370675193915 0, 91.0074135038783 0, 199.70588235294125 0 M199.70588235294125 0 C199.70588235294125 8.990837124474735, 199.70588235294125 17.98167424894947, 199.70588235294125 37.59169550173011 M199.70588235294125 0 C199.70588235294125 14.383608090506296, 199.70588235294125 28.767216181012593, 199.70588235294125 37.59169550173011 M199.70588235294125 37.59169550173011 C152.58380565441712 37.59169550173011, 105.46172895589298 37.59169550173011, 0 37.59169550173011 M199.70588235294125 37.59169550173011 C158.28431744917356 37.59169550173011, 116.86275254540587 37.59169550173011, 0 37.59169550173011 M0 37.59169550173011 C0 26.598232012306532, 0 15.604768522882956, 0 0 M0 37.59169550173011 C0 26.77625049695012, 0 15.960805492170131, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(124.43070263151071 362.6087328723743) rotate(0 66.5 13.5)"><text x="0" y="21" font-family="Helvetica, Segoe UI Emoji" font-size="23.494809688581316px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">delivery date</text></g><g transform="translate(387.78648718559225 361.87284353785617) rotate(0 69.75578583521315 18.03461720393034)"><path d="M0 0 L139.51157167042618 0 L139.51157167042618 36.06923440786065 L0 36.06923440786065" stroke="none" stroke-width="0" fill="#fff"></path><path d="M0 0 C55.43980877578232 0, 110.87961755156464 0, 139.51157167042618 0 M0 0 C38.67123892787831 0, 77.34247785575663 0, 139.51157167042618 0 M139.51157167042618 0 C139.51157167042618 12.794862940982673, 139.51157167042618 25.589725881965347, 139.51157167042618 36.06923440786065 M139.51157167042618 0 C139.51157167042618 12.89935412691385, 139.51157167042618 25.7987082538277, 139.51157167042618 36.06923440786065 M139.51157167042618 36.06923440786065 C88.24394089405709 36.06923440786065, 36.97631011768799 36.06923440786065, 0 36.06923440786065 M139.51157167042618 36.06923440786065 C84.87579098476786 36.06923440786065, 30.240010299109528 36.06923440786065, 0 36.06923440786065 M0 36.06923440786065 C0 24.201030776872482, 0 12.332827145884316, 0 0 M0 36.06923440786065 C0 25.001084232279638, 0 13.932934056698628, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(421.6375334630645 368.1834641515052) rotate(0 4.884998579284627 12.212496448211482)"><text x="0" y="17.42499289642305" font-family="Virgil, Segoe UI Emoji" font-size="19.539994317138444px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(451.4360247967006 367.6949642935774) rotate(0 4.884998579284627 12.212496448211482)"><text x="0" y="17.42499289642305" font-family="Virgil, Segoe UI Emoji" font-size="19.539994317138444px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(538.3889995079655 360.8559662825792) rotate(0 17.34174495646039 17.34174495646039)"><path d="M0 0 L34.68348991292074 0 L34.68348991292074 34.68348991292074 L0 34.68348991292074" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C9.57520347866013 0, 19.15040695732026 0, 34.68348991292074 0 M0 0 C12.829012201846544 0, 25.658024403693087 0, 34.68348991292074 0 M34.68348991292074 0 C34.68348991292074 13.387734282680508, 34.68348991292074 26.775468565361017, 34.68348991292074 34.68348991292074 M34.68348991292074 0 C34.68348991292074 7.41516960577264, 34.68348991292074 14.83033921154528, 34.68348991292074 34.68348991292074 M34.68348991292074 34.68348991292074 C27.256849805847033 34.68348991292074, 19.83020969877332 34.68348991292074, 0 34.68348991292074 M34.68348991292074 34.68348991292074 C20.983841327597055 34.68348991292074, 7.2841927422733725 34.68348991292074, 0 34.68348991292074 M0 34.68348991292074 C0 23.17218993515759, 0 11.660889957394435, 0 0 M0 34.68348991292074 C0 26.586830031075714, 0 18.490170149230686, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(539.3659992238224 361.83296599843425) rotate(0 17.097495027496166 4.396498721356124)"><path d="M0 0 L34.19499005499228 0 L34.19499005499228 8.792997442712293 L0 8.792997442712293" stroke="none" stroke-width="0" fill="#000"></path><path d="M0 0 C12.285038274544192 0, 24.570076549088384 0, 34.19499005499228 0 M0 0 C9.276475028002112 0, 18.552950056004224 0, 34.19499005499228 0 M34.19499005499228 0 C34.19499005499228 2.434006584223475, 34.19499005499228 4.86801316844695, 34.19499005499228 8.792997442712293 M34.19499005499228 0 C34.19499005499228 2.781845972529476, 34.19499005499228 5.563691945058952, 34.19499005499228 8.792997442712293 M34.19499005499228 8.792997442712293 C24.602459615257793 8.792997442712293, 15.009929175523308 8.792997442712293, 0 8.792997442712293 M34.19499005499228 8.792997442712293 C21.001977236583443 8.792997442712293, 7.808964418174604 8.792997442712293, 0 8.792997442712293 M0 8.792997442712293 C0 5.841320005988653, 0 2.8896425692650114, 0 0 M0 8.792997442712293 C0 5.403896656500538, 0 2.0147958702887827, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(546.6934970927516 353.52846841364953) rotate(0 2.9309991475707875 6.838998010998466)"><path d="M0 0 L5.861998295141533 0 L5.861998295141533 13.677996021996911 L0 13.677996021996911" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C1.4406882612954708 0, 2.8813765225909416 0, 5.861998295141533 0 M0 0 C1.4006236417656008 0, 2.8012472835312017 0, 5.861998295141533 0 M5.861998295141533 0 C5.861998295141533 5.3156390105338645, 5.861998295141533 10.631278021067729, 5.861998295141533 13.677996021996911 M5.861998295141533 0 C5.861998295141533 4.455722168129303, 5.861998295141533 8.911444336258606, 5.861998295141533 13.677996021996911 M5.861998295141533 13.677996021996911 C3.5450520464645443 13.677996021996911, 1.2281057977875554 13.677996021996911, 0 13.677996021996911 M5.861998295141533 13.677996021996911 C3.64303247747399 13.677996021996911, 1.4240666598064466 13.677996021996911, 0 13.677996021996911 M0 13.677996021996911 C0 10.243041026991754, 0 6.808086031986596, 0 0 M0 13.677996021996911 C0 8.505417493634637, 0 3.3328389652723622, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(561.348492830605 353.52846841364953) rotate(0 2.9309991475707875 6.838998010998466)"><path d="M0 0 L5.861998295141533 0 L5.861998295141533 13.677996021996911 L0 13.677996021996911" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0 0 C1.4048860706216215 0, 2.809772141243243 0, 5.861998295141533 0 M0 0 C1.9050741409846754 0, 3.810148281969351 0, 5.861998295141533 0 M5.861998295141533 0 C5.861998295141533 2.947701635698273, 5.861998295141533 5.895403271396546, 5.861998295141533 13.677996021996911 M5.861998295141533 0 C5.861998295141533 3.884129481375102, 5.861998295141533 7.768258962750204, 5.861998295141533 13.677996021996911 M5.861998295141533 13.677996021996911 C4.442701754505925 13.677996021996911, 3.0234052138703165 13.677996021996911, 0 13.677996021996911 M5.861998295141533 13.677996021996911 C4.595862491244022 13.677996021996911, 3.32972668734651 13.677996021996911, 0 13.677996021996911 M0 13.677996021996911 C0 9.63321077458749, 0 5.588425527178066, 0 0 M0 13.677996021996911 C0 9.014838182708136, 0 4.3516803434193605, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(555.118531080688 369.9618043772889) rotate(0 0.24424992896422282 12.945246235104264)"><path d="M0 0 C0.10953645508111119 5.805432119298893, 0.21907291016222238 11.610864238597786, 0.4884998579284611 25.89049247020844 M0 0 C0.12451699391601756 6.599400677548931, 0.24903398783203512 13.198801355097862, 0.4884998579284611 25.89049247020844" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(546.0293380288911 368.85340137343337) rotate(0 0.24424992896422282 13.677996021996933)"><path d="M0 0 C0.10716094582593776 6.001012966252514, 0.2143218916518755 12.002025932505028, 0.4884998579284611 27.355992043993822 M0 0 C0.15526133988273694 8.694635033433268, 0.3105226797654739 17.389270066866537, 0.4884998579284611 27.355992043993822" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(564.9494292001057 369.9831125196679) rotate(0 0.7327497868926685 12.456746377175818)"><path d="M0 0 C0.41616099285571023 7.074736878547077, 0.8323219857114205 14.149473757094153, 1.4654995737853833 24.913492754351527 M0 0 C0.45905133818462057 7.803872749138553, 0.9181026763692411 15.607745498277106, 1.4654995737853833 24.913492754351527" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(573.5692973684893 378.145095348862) rotate(0 -16.60899516956772 0)"><path d="M0 0 C-7.2177111304083565 0, -14.435422260816713 0, -33.21799033913535 0 M0 0 C-11.641370495996155 0, -23.28274099199231 0, -33.21799033913535 0" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(573.0940074141797 386.8406683121675) rotate(0 -17.58599488542461 0.48849985792844564)"><path d="M0 0 C-9.749330494322896 0.270814735953414, -19.498660988645792 0.541629471906828, -35.17198977084917 0.9769997158569222 M0 0 C-12.476582768321407 0.3465717435644838, -24.953165536642814 0.6931434871289676, -35.17198977084917 0.9769997158569222" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(124.43146930138187 430.1561042809583) rotate(0 71 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="19.825388200978065px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">delivery location</text></g><g transform="translate(638.9002931167688 425.1997572307075) rotate(0 30.233717006491474 18.33848408590461)"><path d="M0 0 C22.472148607424298 0, 44.944297214848596 0, 60.46743401298301 0 M0 0 C17.41463295067124 0, 34.82926590134248 0, 60.46743401298301 0 M60.46743401298301 0 C60.46743401298301 11.592106789816704, 60.46743401298301 23.184213579633408, 60.46743401298301 36.676968171809314 M60.46743401298301 0 C60.46743401298301 9.014323088289395, 60.46743401298301 18.02864617657879, 60.46743401298301 36.676968171809314 M60.46743401298301 36.676968171809314 C39.47376126896 36.676968171809314, 18.48008852493698 36.676968171809314, 0 36.676968171809314 M60.46743401298301 36.676968171809314 C43.95284995083415 36.676968171809314, 27.438265888685287 36.676968171809314, 0 36.676968171809314 M0 36.676968171809314 C0 26.68601243134865, 0 16.69505669088799, 0 0 M0 36.676968171809314 C0 22.77452447295343, 0 8.872080774097551, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(666.6558365981346 431.1473736909927) rotate(0 0 10.903963510537892)"><path d="M0 0 C0 3.634654503512637, 0 18.173272517563184, 0 21.807927021075823 M0 0 C0 3.634654503512637, 0 18.173272517563184, 0 21.807927021075823" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(666.6558365981346 431.1473736909927) rotate(0 0 10.903963510537892)"><path d="M-3.729375162692038 11.561552972904538 C-2.761486101766064 14.220806312335792, -1.7935970408400899 16.880059651767045, 0 21.807927021075823 M-3.729375162692038 11.561552972904538 C-2.7688984867987685 14.200440951834132, -1.8084218109054992 16.839328930763727, 0 21.807927021075823" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(666.6558365981346 431.1473736909927) rotate(0 0 10.903963510537892)"><path d="M3.729375162692038 11.561552972904538 C2.761486101766064 14.220806312335792, 1.7935970408400899 16.880059651767045, 0 21.807927021075823 M3.729375162692038 11.561552972904538 C2.7688984867987685 14.200440951834132, 1.8084218109054992 16.839328930763727, 0 21.807927021075823" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(102 423.93245619264553) rotate(0 299.5 19)"><path d="M0 0 C193.9767573282123 0, 387.9535146564246 0, 599.0000000000001 0 M0 0 C162.25038655549292 0, 324.50077311098585 0, 599.0000000000001 0 M599.0000000000001 0 C599.0000000000001 10.080071184039117, 599.0000000000001 20.160142368078233, 599.0000000000001 38 M599.0000000000001 0 C599.0000000000001 14.464655616879465, 599.0000000000001 28.92931123375893, 599.0000000000001 38 M599.0000000000001 38 C364.0274778440595 38, 129.05495568811892 38, 0 38 M599.0000000000001 38 C396.98877884596595 38, 194.97755769193174 38, 0 38 M0 38 C0 27.496936300396918, 0 16.99387260079384, 0 0 M0 38 C0 25.07144419848919, 0 12.142888396978378, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g></svg> \ No newline at end of file
diff --git a/backoffice-order-create.price-section.svg b/images/backoffice-order-create.price-section.svg
index e9bf10f3..e9bf10f3 100644
--- a/backoffice-order-create.price-section.svg
+++ b/images/backoffice-order-create.price-section.svg
diff --git a/backoffice-order-create.product-section.svg b/images/backoffice-order-create.product-section.svg
index ceac063a..ceac063a 100644
--- a/backoffice-order-create.product-section.svg
+++ b/images/backoffice-order-create.product-section.svg
diff --git a/backoffice-order-details.claimed.svg b/images/backoffice-order-details.claimed.svg
index 007c296c..007c296c 100644
--- a/backoffice-order-details.claimed.svg
+++ b/images/backoffice-order-details.claimed.svg
diff --git a/backoffice-order-details.paid.svg b/images/backoffice-order-details.paid.svg
index 4d600ecc..4d600ecc 100644
--- a/backoffice-order-details.paid.svg
+++ b/images/backoffice-order-details.paid.svg
diff --git a/backoffice-order-details.refunded.svg b/images/backoffice-order-details.refunded.svg
index c3ced448..c3ced448 100644
--- a/backoffice-order-details.refunded.svg
+++ b/images/backoffice-order-details.refunded.svg
diff --git a/backoffice-order-details.unpaid.svg b/images/backoffice-order-details.unpaid.svg
index 890193ce..890193ce 100644
--- a/backoffice-order-details.unpaid.svg
+++ b/images/backoffice-order-details.unpaid.svg
diff --git a/backoffice-order-list.pagination.svg b/images/backoffice-order-list.pagination.svg
index 1e7dae04..1e7dae04 100644
--- a/backoffice-order-list.pagination.svg
+++ b/images/backoffice-order-list.pagination.svg
diff --git a/backoffice-order-list.svg b/images/backoffice-order-list.svg
index fb8fc12e..fb8fc12e 100644
--- a/backoffice-order-list.svg
+++ b/images/backoffice-order-list.svg
diff --git a/backoffice-order-refund.already.svg b/images/backoffice-order-refund.already.svg
index b2dcd3a4..b2dcd3a4 100644
--- a/backoffice-order-refund.already.svg
+++ b/images/backoffice-order-refund.already.svg
diff --git a/backoffice-order-refund.svg b/images/backoffice-order-refund.svg
index 7bcb0aec..7bcb0aec 100644
--- a/backoffice-order-refund.svg
+++ b/images/backoffice-order-refund.svg
diff --git a/images/backoffice-product-create.stock.svg b/images/backoffice-product-create.stock.svg
new file mode 100644
index 00000000..0ec29939
--- /dev/null
+++ b/images/backoffice-product-create.stock.svg
@@ -0,0 +1,16 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2664.430097077814 3110.5102161527097" width="2664.430097077814" height="3110.5102161527097">
+ <!-- svg-source:excalidraw -->
+
+ <defs>
+ <style>
+ @font-face {
+ font-family: "Virgil";
+ src: url("https://excalidraw.com/Virgil.woff2");
+ }
+ @font-face {
+ font-family: "Cascadia";
+ src: url("https://excalidraw.com/Cascadia.woff2");
+ }
+ </style>
+ </defs>
+ <rect x="0" y="0" width="2664.430097077814" height="3110.5102161527097" fill="#ffffff"></rect><g transform="translate(10 80.94624914970746) rotate(0 412 84.5)"><path d="M0 0 C236.0917525626719 0, 472.1835051253438 0, 824 0 M0 0 C176.35285029634835 0, 352.7057005926967 0, 824 0 M824 0 C824 49.4694261523895, 824 98.938852304779, 824 169 M824 0 C824 67.28842992009595, 824 134.5768598401919, 824 169 M824 169 C617.4895157001913 169, 410.9790314003825 169, 0 169 M824 169 C591.9370339371264 169, 359.8740678742528 169, 0 169 M0 169 C0 117.27438288601115, 0 65.5487657720223, 0 0 M0 169 C0 113.33390512643382, 0 57.66781025286764, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(103 150.94624914970746) rotate(0 25 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Stock</text></g><g transform="translate(195 136.19977029409756) rotate(0 91.5 26.5)"><path d="M0 0 C45.52723533092067 0, 91.05447066184134 0, 183 0 M0 0 C51.992949485499416 0, 103.98589897099883 0, 183 0 M183 0 C183 11.300868693832308, 183 22.601737387664617, 183 53 M183 0 C183 11.438832641299815, 183 22.87766528259963, 183 53 M183 53 C122.95858201207594 53, 62.91716402415186 53, 0 53 M183 53 C130.75365380672739 53, 78.50730761345476 53, 0 53 M0 53 C0 34.84640925144777, 0 16.692818502895534, 0 0 M0 53 C0 40.84659901196137, 0 28.69319802392274, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(223 151.19977029409756) rotate(0 62.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">manage stock</text></g><g transform="translate(907.7142857142858 69.91405600838334) rotate(0 412 208.375)"><path d="M0 0 C254.33701222166422 0, 508.67402444332845 0, 824 0 M0 0 C264.9951364375651 0, 529.9902728751302 0, 824 0 M824 0 C824 153.41329097186681, 824 306.82658194373363, 824 416.75 M824 0 C824 126.50023594351951, 824 253.00047188703903, 824 416.75 M824 416.75 C651.8076281763613 416.75, 479.6152563527226 416.75, 0 416.75 M824 416.75 C609.0305379532277 416.75, 394.06107590645547 416.75, 0 416.75 M0 416.75 C0 306.4687552821124, 0 196.1875105642248, 0 0 M0 416.75 C0 326.79617198703346, 0 236.8423439740669, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1000.7142857142858 139.91405600838334) rotate(0 25 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Stock</text></g><g transform="translate(999.7142857142858 194.41405600838334) rotate(0 57 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">current stock</text></g><g transform="translate(1159.7142857142858 183.41405600838334) rotate(0 49.370370370370324 25)"><path d="M0 0 C20.526187548641513 0, 41.052375097283026 0, 98.74074074074065 0 M0 0 C33.9206452924413 0, 67.8412905848826 0, 98.74074074074065 0 M98.74074074074065 0 C98.74074074074065 15.900936177931726, 98.74074074074065 31.801872355863452, 98.74074074074065 50 M98.74074074074065 0 C98.74074074074065 17.552169584669176, 98.74074074074065 35.10433916933835, 98.74074074074065 50 M98.74074074074065 50 C77.60304118323788 50, 56.465341625735114 50, 0 50 M98.74074074074065 50 C65.00140776341016 50, 31.262074786079666 50, 0 50 M0 50 C0 34.59016109351069, 0 19.18032218702137, 0 0 M0 50 C0 38.90304414089769, 0 27.806088281795382, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1195.3068783068784 196.91405600838334) rotate(0 11 11.5)"><text x="11" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">15</text></g><g transform="translate(908.6428571428569 628.8069131512407) rotate(0 412 199)"><path d="M0 0 C171.06364584192636 0, 342.1272916838527 0, 824 0 M0 0 C255.8546619512141 0, 511.7093239024282 0, 824 0 M824 0 C824 81.9858877783641, 824 163.9717755567282, 824 397.9999999999999 M824 0 C824 144.49592706207184, 824 288.9918541241437, 824 397.9999999999999 M824 397.9999999999999 C531.5596520878374 397.9999999999999, 239.11930417567487 397.9999999999999, 0 397.9999999999999 M824 397.9999999999999 C640.076900806278 397.9999999999999, 456.153801612556 397.9999999999999, 0 397.9999999999999 M0 397.9999999999999 C0 254.37236361447714, 0 110.74472722895439, 0 0 M0 397.9999999999999 C0 268.26489560361944, 0 138.529791207239, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1001.6428571428569 698.8069131512407) rotate(0 25 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Stock</text></g><g transform="translate(1020.6428571428569 753.3069131512407) rotate(0 57 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">current stock</text></g><g transform="translate(1027.6428571428569 833.9735798179072) rotate(0 54 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">next restock</text></g><g transform="translate(1207.6428571428569 838.9735798179072) rotate(0 50 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">15/02/2021</text></g><g transform="translate(1160.6428571428569 827.4735798179072) rotate(0 94.5 23)"><path d="M0 0 C49.514051240589474 0, 99.02810248117895 0, 189 0 M0 0 C62.65167563119903 0, 125.30335126239807 0, 189 0 M189 0 C189 11.8154281610623, 189 23.6308563221246, 189 46 M189 0 C189 13.85625107046217, 189 27.71250214092434, 189 46 M189 46 C139.20686839828267 46, 89.41373679656535 46, 0 46 M189 46 C135.00017379960045 46, 81.0003475992009 46, 0 46 M0 46 C0 35.174531353078784, 0 24.349062706157564, 0 0 M0 46 C0 35.074815454520284, 0 24.14963090904057, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1504.0367965367964 832.2565512018541) rotate(0 42.85000000000002 19.5)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.5074106075470783 4.36293480719127, 3.276278039155605 2.328085597306652, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.2573088406609494 4.650643978407226, 2.776074505383347 2.903503939738564, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C3.3959154886861533 8.287470801869468, 6.658685596504696 4.5340831498099305, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C3.647507052907955 7.998047814865392, 7.161868724948299 3.955237175801777, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C5.4980046620184115 11.966306174529965, 11.124320767230662 5.493969878055035, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C4.42039580787412 13.205953355679192, 8.969103058942078 7.973264240353487, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C6.6630406266275335 16.72309795439064, 13.059790491519845 9.36447900092326, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C6.7918771398395315 16.574888499895042, 13.31746351794384 9.068060091932072, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C7.53269558237936 21.819686714933805, 15.060557227084947 13.159872504933709, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C9.336812067357375 19.74428810766848, 18.668790197040977 9.00907529040306, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C6.6674860457231295 28.912008778352718, 13.591594977833937 20.94673261469564, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C11.063083258220995 23.855452614226436, 22.38278940282967 10.833620286443082, 31.89026953414718 -0.10348448890603734 M2.1061564055129054 40.256230638194594 C14.323628940968602 26.201636217315997, 26.5411014764243 12.1470417964374, 36.877284942009794 0.25662288638767805 M2.1061564055129054 40.256230638194594 C11.888797744895843 29.002589102194243, 21.67143908427878 17.748947566193888, 36.877284942009794 0.25662288638767805 M7.093171813375516 40.6163380134883 C20.458527636515843 25.241254923280316, 33.82388345965617 9.866171833072332, 42.520359378862906 -0.13797931854138312 M7.093171813375516 40.6163380134883 C19.6486159863538 26.172951698266964, 32.20406015933209 11.729565383045628, 42.520359378862906 -0.13797931854138312 M12.736246250228632 40.221735808559245 C25.559914321986906 25.469793194119767, 38.38358239374518 10.717850579680285, 47.50737478672552 0.22212805675232872 M12.736246250228632 40.221735808559245 C22.845389402126045 28.59249690254184, 32.95453255402346 16.963257996524433, 47.50737478672552 0.22212805675232872 M17.723261658091243 40.58184318385296 C27.17710913200512 29.706435723176284, 36.630956605918996 18.83102826249961, 53.15044922357863 -0.1724741481767289 M17.723261658091243 40.58184318385296 C28.21692052825332 28.510269543463995, 38.71057939841539 16.43869590307503, 53.15044922357863 -0.1724741481767289 M22.710277065953854 40.941950559146676 C31.542013545691002 30.782199931955766, 40.37375002542815 20.622449304764856, 58.13746463144125 0.1876332271169865 M22.710277065953854 40.941950559146676 C34.79887591425044 27.035608356498003, 46.88747476254703 13.12926615384933, 58.13746463144125 0.1876332271169865 M28.353351502806966 40.54734835421761 C35.54102822993252 32.27887212601467, 42.72870495705808 24.010395897811723, 63.78053906829436 -0.20696897781207468 M28.353351502806966 40.54734835421761 C40.35904046007414 26.73638307085531, 52.36472941734131 12.92541778749301, 63.78053906829436 -0.20696897781207468 M33.34036691066958 40.90745572951133 C43.7970188346571 28.878453710849296, 54.25367075864462 16.849451692187266, 68.76755447615697 0.1531383974816336 M33.34036691066958 40.90745572951133 C41.24319660752628 31.81629011859939, 49.14602630438298 22.725124507687454, 68.76755447615697 0.1531383974816336 M38.98344134752269 40.51285352458227 C47.70826425099851 30.47609289782541, 56.43308715447433 20.43933227106855, 74.41062891301009 -0.2414638074474169 M38.98344134752269 40.51285352458227 C50.55418139142306 27.20223972991225, 62.12492143532342 13.891625935242235, 74.41062891301009 -0.2414638074474169 M43.97045675538531 40.872960899875984 C54.63078229458096 28.609659188894028, 65.2911078337766 16.346357477912075, 79.3976443208727 0.11864356784629138 M43.97045675538531 40.872960899875984 C53.15853815763985 30.30328233174744, 62.3466195598944 19.7336037636189, 79.3976443208727 0.11864356784629138 M49.613531192238426 40.47835869494692 C60.24594347822508 28.24716750859936, 70.87835576421173 16.0159763222518, 85.04071875772581 -0.27595863708276624 M49.613531192238426 40.47835869494692 C59.758081658722524 28.80838833284445, 69.90263212520662 17.138417970741987, 85.04071875772581 -0.27595863708276624 M54.60054660010103 40.838466070240635 C63.07351194298503 31.091434424308353, 71.54647728586903 21.344402778376075, 88.0595570786169 2.348277478879261 M54.60054660010103 40.838466070240635 C61.491216262386075 32.91165738615166, 68.38188592467111 24.984848702062685, 88.0595570786169 2.348277478879261 M60.24362103695415 40.44386386531157 C66.15965410531828 33.638246327390696, 72.07568717368243 26.832628789469823, 88.45415928354596 7.991351915732373 M60.24362103695415 40.44386386531157 C69.49393434923996 29.802595673962045, 78.74424766152576 19.161327482612517, 88.45415928354596 7.991351915732373 M65.23063644481675 40.80397124060529 C70.53531559049588 34.70163594097189, 75.839994736175 28.599300641338488, 88.19270245948451 14.389135932808273 M65.23063644481675 40.80397124060529 C73.30286312200644 31.517936695239655, 81.37508979919612 22.23190214987402, 88.19270245948451 14.389135932808273 M70.87371088166988 40.40936903567623 C75.35165630103094 35.25808209598322, 79.82960172039202 30.10679515629021, 87.93124563542307 20.786919949884158 M70.87371088166988 40.40936903567623 C76.73927055609427 33.66181449554887, 82.60483023051864 26.9142599554215, 87.93124563542307 20.786919949884158 M75.8607262895325 40.76947641096994 C79.66673358224277 36.39116586378327, 83.47274087495305 32.0128553165966, 88.32584784035213 26.429994386737274 M75.8607262895325 40.76947641096994 C78.5739796905923 37.64823541760579, 81.2872330916521 34.52699442424164, 88.32584784035213 26.429994386737274 M81.5038007263856 40.374874206040886 C83.39465042796638 38.19970044653909, 85.28550012954716 36.02452668703729, 88.06439101629068 32.82777840381317 M81.5038007263856 40.374874206040886 C83.53537583556748 38.037814383541495, 85.56695094474935 35.7007545610421, 88.06439101629068 32.82777840381317" stroke="#fa5252" stroke-width="0.5" fill="none"></path><path d="M0 0 C27.382204342065425 0, 54.76440868413085 0, 85.70000000000013 0 M0 0 C32.83631051179958 0, 65.67262102359916 0, 85.70000000000013 0 M85.70000000000013 0 C85.70000000000013 10.997829736489804, 85.70000000000013 21.995659472979607, 85.70000000000013 39 M85.70000000000013 0 C85.70000000000013 11.259689829032869, 85.70000000000013 22.519379658065738, 85.70000000000013 39 M85.70000000000013 39 C64.52176900905567 39, 43.343538018111204 39, 0 39 M85.70000000000013 39 C67.73251752677383 39, 49.76503505354754 39, 0 39 M0 39 C0 27.597405128460377, 0 16.194810256920753, 0 0 M0 39 C0 27.376256355363875, 0 15.75251271072775, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1518.1367965367963 840.0565512018541) rotate(0 25 11.5)"><text x="25" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">never</text></g><g transform="translate(999.37012987013 903.4373024460815) rotate(0 288.49999999999994 28.5)"><path d="M0 0 C221.61191750867292 0, 443.22383501734583 0, 576.9999999999999 0 M0 0 C148.48949075983836 0, 296.9789815196767 0, 576.9999999999999 0 M576.9999999999999 0 C576.9999999999999 18.23236775575206, 576.9999999999999 36.46473551150412, 576.9999999999999 57 M576.9999999999999 0 C576.9999999999999 20.396188223082575, 576.9999999999999 40.79237644616515, 576.9999999999999 57 M576.9999999999999 57 C347.06813987987107 57, 117.13627975974231 57, 0 57 M576.9999999999999 57 C383.78149965358887 57, 190.5629993071779 57, 0 57 M0 57 C0 45.01051211776212, 0 33.02102423552424, 0 0 M0 57 C0 37.25637744097039, 0 17.51275488194078, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1494.3701298701299 903.4373024460815) rotate(0 41 29)"><path d="M0 0 C24.34247198160738 0, 48.68494396321476 0, 82 0 M0 0 C16.84486520532519 0, 33.68973041065038 0, 82 0 M82 0 C82 23.11392058711499, 82 46.22784117422998, 82 58 M82 0 C82 13.750576350279154, 82 27.501152700558308, 82 58 M82 58 C62.860811912454665 58, 43.72162382490933 58, 0 58 M82 58 C56.11744595523923 58, 30.234891910478467 58, 0 58 M0 58 C0 44.30942313093692, 0 30.61884626187384, 0 0 M0 58 C0 36.32924136202782, 0 14.658482724055645, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(1533.3701298701299 915.4373024460815) rotate(0 0 17)"><path d="M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34 M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1533.3701298701299 915.4373024460815) rotate(0 0 17)"><path d="M-5.814342436536368 18.025225446639556 C-3.6026222832168626 24.101876626037612, -1.3909021298973574 30.17852780543567, 0 34 M-5.814342436536368 18.025225446639556 C-3.699884998619726 23.834649511713405, -1.585427560703084 29.644073576787253, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1533.3701298701299 915.4373024460815) rotate(0 0 17)"><path d="M5.814342436536368 18.025225446639556 C3.6026222832168626 24.101876626037612, 1.3909021298973574 30.17852780543567, 0 34 M5.814342436536368 18.025225446639556 C3.699884998619726 23.834649511713405, 1.585427560703084 29.644073576787253, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(1030.3560452925694 919.4373024460815) rotate(0 35.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">address</text></g><g transform="translate(979.594140530665 313.37777863655765) rotate(0 288.49999999999994 28.5)"><path d="M0 0 C183.09519919259472 0, 366.19039838518944 0, 576.9999999999999 0 M0 0 C191.24218815611673 0, 382.48437631223345 0, 576.9999999999999 0 M576.9999999999999 0 C576.9999999999999 21.60299933133647, 576.9999999999999 43.20599866267294, 576.9999999999999 57 M576.9999999999999 0 C576.9999999999999 18.814047324378045, 576.9999999999999 37.62809464875609, 576.9999999999999 57 M576.9999999999999 57 C375.89746348159383 57, 174.79492696318772 57, 0 57 M576.9999999999999 57 C408.40211005760347 57, 239.80422011520704 57, 0 57 M0 57 C0 39.55012987079098, 0 22.100259741581972, 0 0 M0 57 C0 34.29172115949913, 0 11.583442318998273, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1474.5941405306648 313.37777863655765) rotate(0 41 29)"><path d="M0 0 C23.301106604374947 0, 46.602213208749895 0, 82 0 M0 0 C20.47363549526781 0, 40.94727099053562 0, 82 0 M82 0 C82 17.889156678505245, 82 35.77831335701049, 82 58 M82 0 C82 14.935910755209626, 82 29.871821510419252, 82 58 M82 58 C53.102421215735376 58, 24.20484243147075 58, 0 58 M82 58 C60.69060039464384 58, 39.38120078928768 58, 0 58 M0 58 C0 35.32809809129685, 0 12.656196182593703, 0 0 M0 58 C0 39.14703913349658, 0 20.29407826699316, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(1513.5941405306648 325.37777863655765) rotate(0 0 17)"><path d="M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34 M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1513.5941405306648 325.37777863655765) rotate(0 0 17)"><path d="M-5.814342436536368 18.025225446639556 C-4.189382644804416 22.489765781944783, -2.5644228530724638 26.954306117250006, 0 34 M-5.814342436536368 18.025225446639556 C-4.477115144868706 21.699227235174916, -3.1398878532010444 25.37322902371028, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1513.5941405306648 325.37777863655765) rotate(0 0 17)"><path d="M5.814342436536368 18.025225446639556 C4.189382644804416 22.489765781944783, 2.5644228530724638 26.954306117250006, 0 34 M5.814342436536368 18.025225446639556 C4.477115144868706 21.699227235174916, 3.1398878532010444 25.37322902371028, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(1010.5800559531045 329.37777863655765) rotate(0 35.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">address</text></g><g transform="translate(911.0870972286061 1169.8355253211091) rotate(0 412 210.2500000000001)"><path d="M0 0 C218.95360033735636 0, 437.9072006747127 0, 824 0 M0 0 C209.57695072665814 0, 419.1539014533163 0, 824 0 M824 0 C824 105.35239861519078, 824 210.70479723038156, 824 420.5 M824 0 C824 150.35835648789072, 824 300.71671297578143, 824 420.5 M824 420.5 C503.3142883516848 420.5, 182.62857670336962 420.5, 0 420.5 M824 420.5 C525.6960808418692 420.5, 227.3921616837382 420.5, 0 420.5 M0 420.5 C0 301.00011278777384, 0 181.50022557554766, 0 0 M0 420.5 C0 277.7357025532517, 0 134.97140510650348, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1004.0870972286061 1239.8355253211091) rotate(0 25 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Stock</text></g><g transform="translate(1003.0870972286061 1294.3355253211091) rotate(0 57 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">current stock</text></g><g transform="translate(1015.4669520449852 1414.5492479492834) rotate(0 288.5 28.499999999999886)"><path d="M0 0 C191.88294327305627 0, 383.76588654611254 0, 576.9999999999999 0 M0 0 C153.981226036977 0, 307.962452073954 0, 576.9999999999999 0 M576.9999999999999 0 C576.9999999999999 18.94759962530807, 576.9999999999999 37.89519925061614, 576.9999999999999 57 M576.9999999999999 0 C576.9999999999999 16.581719528418034, 576.9999999999999 33.16343905683607, 576.9999999999999 57 M576.9999999999999 57 C420.6865388090721 57, 264.37307761814435 57, 0 57 M576.9999999999999 57 C439.98495214777057 57, 302.96990429554126 57, 0 57 M0 57 C0 38.82633978752419, 0 20.65267957504838, 0 0 M0 57 C0 39.23593317987397, 0 21.471866359747942, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1510.4669520449852 1414.5492479492834) rotate(0 41 28.999999999999886)"><path d="M0 0 C20.85595868881792 0, 41.71191737763584 0, 82 0 M0 0 C20.54434408191592 0, 41.08868816383184 0, 82 0 M82 0 C82 20.739083653502167, 82 41.478167307004334, 82 58 M82 0 C82 22.57253795582801, 82 45.14507591165602, 82 58 M82 58 C52.31441581193357 58, 22.62883162386715 58, 0 58 M82 58 C58.69681153055281 58, 35.39362306110561 58, 0 58 M0 58 C0 38.30837276596576, 0 18.616745531931514, 0 0 M0 58 C0 42.259131410531694, 0 26.518262821063395, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(1549.4669520449852 1426.5492479492834) rotate(0 0 16.999999999999886)"><path d="M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34 M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1549.4669520449852 1426.5492479492834) rotate(0 0 16.999999999999886)"><path d="M-5.814342436536368 18.025225446639556 C-4.113869358350213 22.697236831346512, -2.4133962801640587 27.369248216053464, 0 34 M-5.814342436536368 18.025225446639556 C-4.337132291635999 22.083826963542613, -2.85992214673563 26.142428480445666, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1549.4669520449852 1426.5492479492834) rotate(0 0 16.999999999999886)"><path d="M5.814342436536368 18.025225446639556 C4.113869358350213 22.697236831346512, 2.4133962801640587 27.369248216053464, 0 34 M5.814342436536368 18.025225446639556 C4.337132291635999 22.083826963542613, 2.85992214673563 26.142428480445666, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(1046.4528674674248 1430.5492479492832) rotate(0 35.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">address</text></g><g transform="translate(1412.0870972286057 122.20172403965671) rotate(0 83.875 26.5)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.7173956115841835 4.121374692556808, 3.6962480472298154 1.8449653680377276, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.53886432158337 4.326751448274156, 3.339185467228188 2.2557188794724237, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C3.454961933751928 8.219545636907089, 6.776778486636245 4.398232819885173, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C2.266605675249538 9.586593133211604, 4.400065969631465 7.1323278124942, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C5.998957222391963 11.390026175559758, 12.126225887977766 4.341409880114616, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C5.228720528642109 12.276082134131954, 10.585752500478057 6.1135217972590095, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C7.703031796699608 15.52672496855091, 15.139772831663993 6.971733029243808, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C5.370490594102075 18.21000667656041, 10.474690426468928 12.33829644526281, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C7.3456726381002575 22.034832001457943, 14.686511338526742 13.59016307798198, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C9.026548904733454 20.101205047875514, 18.048263871793136 9.722909170817125, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C9.850964347063032 25.24983591541769, 19.958551580513742 13.622386888825588, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C9.221483318128827 25.973971004048572, 18.699589522645333 15.07065706608735, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C13.353319137344942 27.317849960621473, 26.5686589561485 12.11534054238004, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C12.917833983670329 27.818818323222533, 25.697688648799275 13.11727726758216, 36.877284942009794 0.25662288638767805 M-0.12347750552006431 48.9181433959388 C10.175775454041249 37.07020817328198, 20.475028413602562 25.222272950625165, 42.520359378862906 -0.13797931854138312 M-0.12347750552006431 48.9181433959388 C9.746254045955597 37.5643160313688, 19.61598559743126 26.210488666798796, 42.520359378862906 -0.13797931854138312 M0.9271837283995019 53.806508252569145 C18.728587858763337 33.32833533682499, 36.52999198912717 12.850162421080846, 47.50737478672552 0.22212805675232872 M0.9271837283995019 53.806508252569145 C16.271137215299515 36.155308919370725, 31.615090702199527 18.504109586172298, 47.50737478672552 0.22212805675232872 M5.914199136262113 54.16661562786285 C23.49673440300238 33.94022253815562, 41.07926966974265 13.713829448448386, 53.15044922357863 -0.1724741481767289 M5.914199136262113 54.16661562786285 C22.864289477153022 34.66776720015996, 39.81437981804393 15.168918772457062, 53.15044922357863 -0.1724741481767289 M11.557273573115229 53.772013422933796 C22.848484740685947 40.7829608164994, 34.13969590825667 27.79390821006499, 58.13746463144125 0.1876332271169865 M11.557273573115229 53.772013422933796 C27.778619477682486 35.111489571715715, 43.99996538224974 16.450965720497635, 58.13746463144125 0.1876332271169865 M16.544288980977836 54.13212079822751 C27.664794442473266 41.33944264299447, 38.78529990396869 28.546764487761436, 63.78053906829436 -0.20696897781207468 M16.544288980977836 54.13212079822751 C31.45706359913156 36.976936013496115, 46.36983821728528 19.82175122876471, 63.78053906829436 -0.20696897781207468 M22.18736341783096 53.73751859329845 C35.13162478449539 38.84684926227623, 48.075886151159835 23.956179931254013, 68.76755447615697 0.1531383974816336 M22.18736341783096 53.73751859329845 C33.69096689012845 40.504136589569505, 45.19457036242595 27.27075458584056, 68.76755447615697 0.1531383974816336 M27.174378825693566 54.09762596859217 C43.810054153418044 34.96047063879192, 60.44572948114252 15.82331530899166, 74.41062891301009 -0.2414638074474169 M27.174378825693566 54.09762596859217 C44.820114437100386 33.798529199055054, 62.46585004850721 13.499432429517938, 74.41062891301009 -0.2414638074474169 M32.817453262546685 53.703023763663104 C49.97269154179106 33.968179628871866, 67.12792982103542 14.23333549408062, 79.3976443208727 0.11864356784629138 M32.817453262546685 53.703023763663104 C49.16607414542128 34.89608679837052, 65.51469502829588 16.089149833077933, 79.3976443208727 0.11864356784629138 M37.80446867040929 54.06313113895682 C53.664216718620374 35.81857803780972, 69.52396476683145 17.574024936662624, 85.04071875772581 -0.27595863708276624 M37.80446867040929 54.06313113895682 C53.71031346445203 35.76554979772929, 69.61615825849475 17.467968456501765, 85.04071875772581 -0.27595863708276624 M43.447543107262405 53.668528934027755 C54.41543216278025 41.05141587065494, 65.38332121829811 28.43430280728213, 90.02773416558841 0.08414873821094204 M43.447543107262405 53.668528934027755 C60.61312426753425 33.92178667566286, 77.7787054278061 14.175044417297954, 90.02773416558841 0.08414873821094204 M48.43455851512502 54.02863630932147 C66.93170216944668 32.750106625561266, 85.42884582376834 11.471576941801061, 95.67080860244155 -0.3104534667181156 M48.43455851512502 54.02863630932147 C59.88172162803239 40.86018151192713, 71.32888474093976 27.69172671453279, 95.67080860244155 -0.3104534667181156 M54.07763295197813 53.63403410439241 C70.07482934877166 35.23136476541137, 86.07202574556518 16.828695426430336, 100.65782401030415 0.049653908575599814 M54.07763295197813 53.63403410439241 C67.6147605641235 38.0613501748612, 81.15188817626887 22.488666245329977, 100.65782401030415 0.049653908575599814 M59.064648359840746 53.99414147968613 C69.32977228979794 42.185467214455, 79.59489621975513 30.37679294922387, 106.30089844715727 -0.3449482963534578 M59.064648359840746 53.99414147968613 C71.3619643394091 39.84769768317661, 83.65928031897745 25.701253886667097, 106.30089844715727 -0.3449482963534578 M64.70772279669386 53.59953927475706 C83.26681476468622 32.24974620806945, 101.82590673267859 10.899953141381843, 111.28791385501988 0.015159078940250481 M64.70772279669386 53.59953927475706 C78.26906752069534 37.99899674483243, 91.83041224469684 22.398454214907797, 111.28791385501988 0.015159078940250481 M69.69473820455647 53.959646650050786 C83.79703187510646 37.73681354209728, 97.89932554565644 21.513980434143782, 116.2749292628825 0.375266454233973 M69.69473820455647 53.959646650050786 C88.0232089730638 32.87515292528618, 106.35167974157113 11.790659200521574, 116.2749292628825 0.375266454233973 M75.3378126414096 53.56504444512172 C86.93044099155067 40.22925103446481, 98.52306934169175 26.8934576238079, 121.9180036997356 -0.019335750695091747 M75.3378126414096 53.56504444512172 C85.89947527144335 41.415241427804126, 96.46113790147712 29.265438410486535, 121.9180036997356 -0.019335750695091747 M80.3248280492722 53.92515182041544 C91.03408820637159 41.605557270977584, 101.74334836347099 29.285962721539736, 126.9050191075982 0.34077162459862365 M80.3248280492722 53.92515182041544 C97.90171544146804 33.70525586715205, 115.4786028336639 13.485359913888658, 126.9050191075982 0.34077162459862365 M85.96790248612533 53.53054961548638 C103.91797705566042 32.88135092343194, 121.8680516251955 12.23215223137749, 132.54809354445132 -0.05383058033042687 M85.96790248612533 53.53054961548638 C101.66089334007648 35.477828722292706, 117.35388419402764 17.425107829099034, 132.54809354445132 -0.05383058033042687 M90.95491789398793 53.89065699078009 C108.32841377881171 33.90473620189459, 125.70190966363549 13.9188154130091, 137.53510895231395 0.3062767949632672 M90.95491789398793 53.89065699078009 C108.67003675500621 33.511743922899626, 126.38515561602449 13.132830855019158, 137.53510895231395 0.3062767949632672 M96.59799233084104 53.49605478585103 C107.80858362942544 40.59974472969279, 119.01917492800983 27.703434673534552, 143.17818338916706 -0.0883254099657762 M96.59799233084104 53.49605478585103 C112.61753868732575 35.0676747593386, 128.63708504381046 16.639294732826166, 143.17818338916706 -0.0883254099657762 M101.58500773870365 53.85616216114475 C120.14001076986757 32.511072878203706, 138.69501380103148 11.165983595262652, 148.16519879702966 0.2717819653279321 M101.58500773870365 53.85616216114475 C115.72587718093787 37.588952704161514, 129.8667466231721 21.321743247178283, 148.16519879702966 0.2717819653279321 M107.22808217555678 53.46155995621568 C120.72671425385484 37.93316007264153, 134.2253463321529 22.404760189067368, 153.8082732338828 -0.12282023960112554 M107.22808217555678 53.46155995621568 C123.66510766343758 34.55292512627111, 140.10213315131838 15.644290296326545, 153.8082732338828 -0.12282023960112554 M112.21509758341939 53.8216673315094 C129.19705003766725 34.28616573521338, 146.1790024919151 14.750664138917358, 158.7952886417454 0.23728713569258275 M112.21509758341939 53.8216673315094 C125.31139171728925 38.75610430823168, 138.4076858511591 23.690541284953955, 158.7952886417454 0.23728713569258275 M117.20211299128198 54.181774706803104 C133.7292754332167 35.169449172591754, 150.25643787515145 16.157123638380398, 164.4383630785985 -0.15731506923647487 M117.20211299128198 54.181774706803104 C133.81536100577716 35.0704190496007, 150.42860902027232 15.959063392398306, 164.4383630785985 -0.15731506923647487 M122.8451874281351 53.78717250187405 C133.05985181490902 42.036545300963766, 143.27451620168293 30.285918100053483, 168.7693194574706 0.9575018862800135 M122.8451874281351 53.78717250187405 C140.28991833384504 33.71930519547341, 157.73464923955493 13.651437889072767, 168.7693194574706 0.9575018862800135 M127.83220283599772 54.14727987716777 C139.23328157673114 41.03183908558893, 150.6343603174646 27.916398294010087, 168.50786263340916 7.355285903355906 M127.83220283599772 54.14727987716777 C140.48760654926735 39.58890326479492, 153.143010262537 25.030526652422076, 168.50786263340916 7.355285903355906 M133.47527727285083 53.752677672238704 C144.62918479252608 40.92157484453947, 155.7830923122013 28.09047201684024, 168.90246483833823 12.998360340209018 M133.47527727285083 53.752677672238704 C144.07958096052596 41.55382172935999, 154.6838846482011 29.354965786481277, 168.90246483833823 12.998360340209018 M138.46229268071346 54.11278504753242 C146.9895790886307 44.30326416453928, 155.51686549654798 34.493743281546145, 168.6410080142768 19.39614435728491 M138.46229268071346 54.11278504753242 C147.05382327377777 44.229359683598474, 155.64535386684204 34.34593431966452, 168.6410080142768 19.39614435728491 M144.10536711756657 53.718182842603355 C151.0098749112423 45.77545520934758, 157.91438270491798 37.83272757609179, 169.03561021920584 25.03921879413801 M144.10536711756657 53.718182842603355 C150.88646680478465 45.91741999621139, 157.66756649200275 38.11665714981944, 169.03561021920584 25.03921879413801 M149.09238252542917 54.07829021789707 C153.03681122133102 49.54074406159562, 156.98123991723287 45.003197905294165, 168.7741533951444 31.437002811213915 M149.09238252542917 54.07829021789707 C155.1688205945165 47.088147834783996, 161.2452586636038 40.098005451670915, 168.7741533951444 31.437002811213915 M154.73545696228229 53.68368801296802 C159.36574426257135 48.35715178635883, 163.9960315628604 43.03061555974963, 168.51269657108293 37.83478682828981 M154.73545696228229 53.68368801296802 C159.73862405330902 47.928202655403005, 164.74179114433576 42.172717297838, 168.51269657108293 37.83478682828981 M159.72247237014489 54.04379538826172 C161.7409058583154 51.721853271393485, 163.7593393464859 49.39991115452525, 168.907298776012 43.47786126514291 M159.72247237014489 54.04379538826172 C162.50026141307723 50.848314631347684, 165.27805045600957 47.65283387443364, 168.907298776012 43.47786126514291 M165.36554680699803 53.64919318333267 C166.0601001263845 52.850200987579996, 166.75465344577094 52.05120879182733, 168.64584195195056 49.875645282218805 M165.36554680699803 53.64919318333267 C166.5819819107356 52.24984467055833, 167.79841701447322 50.850496157783994, 168.64584195195056 49.875645282218805" stroke="#fa5252" stroke-width="0.5" fill="none"></path><path d="M0 0 C46.183000835520254 0, 92.36600167104051 0, 167.7500000000001 0 M0 0 C36.24056315112396 0, 72.48112630224792 0, 167.7500000000001 0 M167.7500000000001 0 C167.7500000000001 18.842396629508585, 167.7500000000001 37.68479325901717, 167.7500000000001 53 M167.7500000000001 0 C167.7500000000001 16.167132444027814, 167.7500000000001 32.33426488805563, 167.7500000000001 53 M167.7500000000001 53 C102.15453257735359 53, 36.55906515470707 53, 0 53 M167.7500000000001 53 C129.04311365347831 53, 90.33622730695649 53, 0 53 M0 53 C0 38.442475789133454, 0 23.884951578266914, 0 0 M0 53 C0 40.237482499238105, 0 27.474964998476207, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1442.0870972286054 137.2017240396567) rotate(0 58 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">without stock</text></g><g transform="translate(1412.0870972286061 1209.701724039657) rotate(0 79.5 26.5)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.6763342954413682 4.168610333406417, 3.614125414944185 1.9394366497369457, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.1857802863737288 4.732928167473438, 2.633017396808906 3.068072317870987, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C2.349949477829196 9.4907170557863, 4.566753574790781 6.940575657643593, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C2.9945686047466356 8.749167577490088, 5.85599182862566 5.457476701051167, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C5.2124176579807555 12.294836441487785, 10.55314675915535 6.151030411970671, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C4.955555809340896 12.590322197183463, 10.039423061875631 6.742001923362029, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C6.076761123300264 17.397535372819554, 11.887231484865305 10.713353837781092, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C6.779310011319332 16.589345327514167, 13.292329260903442 9.096973747170317, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C10.242782297882494 18.70208857658965, 20.480730658091215 6.924676228245396, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C7.852918654132539 21.451312209925682, 15.701003370591305 12.423123494917462, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C11.518475193802992 23.331584118629685, 23.293573273993662 9.785883295249576, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C6.37849692552965 29.24445273225389, 13.013616737446979 21.61162052249799, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C14.51001094359821 25.987228249816308, 28.882042568655038 9.45409712076971, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C13.87108758374623 26.722225497625526, 27.604195848951075 10.924091616388147, 36.877284942009794 0.25662288638767805 M-0.12347750552006431 48.9181433959388 C9.59161271356494 37.742210534601575, 19.306702932649944 26.56627767326435, 42.520359378862906 -0.13797931854138312 M-0.12347750552006431 48.9181433959388 C10.07668795276822 37.18419530429695, 20.276853411056504 25.450247212655093, 42.520359378862906 -0.13797931854138312 M0.9271837283995019 53.806508252569145 C19.295938194460234 32.67567343481305, 37.66469266052097 11.54483861705696, 47.50737478672552 0.22212805675232872 M0.9271837283995019 53.806508252569145 C15.31044142937061 37.26046300045369, 29.693699130341717 20.714417748338235, 47.50737478672552 0.22212805675232872 M5.914199136262113 54.16661562786285 C17.356716674322968 41.00350495300532, 28.79923421238382 27.840394278147787, 53.15044922357863 -0.1724741481767289 M5.914199136262113 54.16661562786285 C16.72681856170508 41.72811984152908, 27.53943798714805 29.289624055195297, 53.15044922357863 -0.1724741481767289 M11.557273573115229 53.772013422933796 C27.133354011702025 35.853782578050385, 42.709434450288825 17.935551733166967, 58.13746463144125 0.1876332271169865 M11.557273573115229 53.772013422933796 C28.228403248938907 34.59407253118161, 44.89953292476258 15.416131639429423, 58.13746463144125 0.1876332271169865 M16.544288980977836 54.13212079822751 C31.813370743359187 36.567051531509506, 47.082452505740534 19.001982264791508, 63.78053906829436 -0.20696897781207468 M16.544288980977836 54.13212079822751 C27.78688901826427 41.198988900311456, 39.0294890555507 28.2658570023954, 63.78053906829436 -0.20696897781207468 M22.18736341783096 53.73751859329845 C37.50897302708171 36.11202295104255, 52.83058263633245 18.48652730878665, 68.76755447615697 0.1531383974816336 M22.18736341783096 53.73751859329845 C39.292479008292844 34.06033401616755, 56.39759459875472 14.383149439036657, 68.76755447615697 0.1531383974816336 M27.174378825693566 54.09762596859217 C37.44142796809184 42.286736999791636, 47.70847711049011 30.4758480309911, 74.41062891301009 -0.2414638074474169 M27.174378825693566 54.09762596859217 C39.98323217008107 39.36272574848162, 52.79208551446856 24.627825528371073, 74.41062891301009 -0.2414638074474169 M32.817453262546685 53.703023763663104 C50.442127839427194 33.42815494286845, 68.0668024163077 13.153286122073801, 79.3976443208727 0.11864356784629138 M32.817453262546685 53.703023763663104 C45.6266603288556 38.96771663302921, 58.435867395164514 24.232409502395328, 79.3976443208727 0.11864356784629138 M37.80446867040929 54.06313113895682 C47.43497861338879 42.9844967551254, 57.065488556368294 31.905862371293974, 85.04071875772581 -0.27595863708276624 M37.80446867040929 54.06313113895682 C55.52889401123652 33.673512190721695, 73.25331935206376 13.283893242486577, 85.04071875772581 -0.27595863708276624 M43.447543107262405 53.668528934027755 C55.83551580208621 39.417796516385934, 68.22348849691002 25.167064098744106, 90.02773416558841 0.08414873821094204 M43.447543107262405 53.668528934027755 C53.30706930107239 42.32644149050074, 63.166595494882365 30.98435404697373, 90.02773416558841 0.08414873821094204 M48.43455851512502 54.02863630932147 C67.0908023826447 32.567082766716126, 85.74704625016437 11.10552922411079, 95.67080860244155 -0.3104534667181156 M48.43455851512502 54.02863630932147 C64.45882481017543 35.59482661459903, 80.48309110522584 17.161016919876587, 95.67080860244155 -0.3104534667181156 M54.07763295197813 53.63403410439241 C66.08133276375455 39.82535707116004, 78.08503257553096 26.016680037927674, 100.65782401030415 0.049653908575599814 M54.07763295197813 53.63403410439241 C72.70393937857786 32.206919648014434, 91.33024580517758 10.779805191636449, 100.65782401030415 0.049653908575599814 M59.064648359840746 53.99414147968613 C70.1902433741227 41.19560846372059, 81.31583838840466 28.397075447755043, 106.30089844715727 -0.3449482963534578 M59.064648359840746 53.99414147968613 C77.69525417082781 32.562081147338446, 96.32585998181489 11.130020814990765, 106.30089844715727 -0.3449482963534578 M64.70772279669386 53.59953927475706 C74.13910111598257 42.74997961969814, 83.5704794352713 31.90041996463922, 111.28791385501988 0.015159078940250481 M64.70772279669386 53.59953927475706 C76.55944342570267 39.96569429193582, 88.41116405471146 26.33184930911458, 111.28791385501988 0.015159078940250481 M69.69473820455647 53.959646650050786 C79.16741721515874 43.06257598450837, 88.64009622576101 32.16550531896595, 116.2749292628825 0.375266454233973 M69.69473820455647 53.959646650050786 C84.3289502908371 37.1249114014217, 98.96316237711773 20.290176152792604, 116.2749292628825 0.375266454233973 M75.3378126414096 53.56504444512172 C86.14180353400351 41.13647465037817, 96.94579442659742 28.70790485563462, 121.9180036997356 -0.019335750695091747 M75.3378126414096 53.56504444512172 C88.49005672829291 38.43511836351181, 101.64230081517624 23.305192281901906, 121.9180036997356 -0.019335750695091747 M80.3248280492722 53.92515182041544 C94.71918853078526 37.36633428033221, 109.11354901229831 20.807516740248992, 126.9050191075982 0.34077162459862365 M80.3248280492722 53.92515182041544 C94.9563456434856 37.09351623033399, 109.587863237699 20.261880640252535, 126.9050191075982 0.34077162459862365 M85.96790248612533 53.53054961548638 C98.10578744757035 39.56751022535702, 110.24367240901537 25.604470835227655, 132.54809354445132 -0.05383058033042687 M85.96790248612533 53.53054961548638 C103.80023219455592 33.01680089175919, 121.63256190298651 12.503052168031992, 132.54809354445132 -0.05383058033042687 M90.95491789398793 53.89065699078009 C109.39582213972629 32.67682334589489, 127.83672638546466 11.462989701009697, 137.53510895231395 0.3062767949632672 M90.95491789398793 53.89065699078009 C107.35244279276296 35.027462390609415, 123.74996769153798 16.164267790438743, 137.53510895231395 0.3062767949632672 M96.59799233084104 53.49605478585103 C109.90482235845376 38.18829792182548, 123.21165238606649 22.88054105779993, 143.17818338916706 -0.0883254099657762 M96.59799233084104 53.49605478585103 C112.77249588422322 34.88941689555622, 128.9469994376054 16.282779005261403, 143.17818338916706 -0.0883254099657762 M101.58500773870365 53.85616216114475 C112.7724984269507 40.98642631730611, 123.95998911519776 28.11669047346747, 148.16519879702966 0.2717819653279321 M101.58500773870365 53.85616216114475 C112.20006631530816 41.644934133818495, 122.81512489191269 29.433706106492235, 148.16519879702966 0.2717819653279321 M107.22808217555678 53.46155995621568 C120.61208073460944 38.06503085158998, 133.9960792936621 22.66850174696429, 153.8082732338828 -0.12282023960112554 M107.22808217555678 53.46155995621568 C123.95754253771364 34.2165172857343, 140.6870028998705 14.971474615252909, 153.8082732338828 -0.12282023960112554 M112.21509758341939 53.8216673315094 C123.90092493152434 40.3786607380102, 135.58675227962928 26.935654144510988, 158.7952886417454 0.23728713569258275 M112.21509758341939 53.8216673315094 C125.43723812719647 38.611334574112234, 138.65937867097352 23.401001816715073, 158.7952886417454 0.23728713569258275 M117.20211299128198 54.181774706803104 C130.99364885222906 38.316427565314, 144.7851847131761 22.4510804238249, 159.18989084667447 5.880361572545695 M117.20211299128198 54.181774706803104 C129.560359585114 39.96523825661208, 141.91860617894605 25.74870180642106, 159.18989084667447 5.880361572545695 M122.8451874281351 53.78717250187405 C136.18922449133777 38.43661383957947, 149.53326155454045 23.086055177284887, 158.928434022613 12.278145589621587 M122.8451874281351 53.78717250187405 C133.82487607659277 41.15648555956519, 144.80456472505045 28.525798617256328, 158.928434022613 12.278145589621587 M127.83220283599772 54.14727987716777 C135.85614577605108 44.916789417586315, 143.88008871610447 35.686298958004855, 159.32303622754208 17.921220026474714 M127.83220283599772 54.14727987716777 C134.7825839478684 46.15178102792611, 141.73296505973906 38.15628217868446, 159.32303622754208 17.921220026474714 M133.47527727285083 53.752677672238704 C142.9837100332666 42.81447702247116, 152.49214279368235 31.876276372703618, 159.0615794034806 24.319004043550592 M133.47527727285083 53.752677672238704 C138.9946597866402 47.40335440100733, 144.51404230042957 41.05403112977595, 159.0615794034806 24.319004043550592 M138.46229268071346 54.11278504753242 C146.49336568920856 44.87409238247427, 154.52443869770366 35.63539971741612, 158.80012257941917 30.716788060626484 M138.46229268071346 54.11278504753242 C144.5317253147659 47.13070149556227, 150.60115794881838 40.14861794359212, 158.80012257941917 30.716788060626484 M144.10536711756657 53.718182842603355 C149.59412307147716 47.4040913982784, 155.08287902538774 41.08999995395345, 159.19472478434824 36.3598624974796 M144.10536711756657 53.718182842603355 C149.94297087583203 47.00278790522013, 155.7805746340975 40.28739296783691, 159.19472478434824 36.3598624974796 M149.09238252542917 54.07829021789707 C151.6516127612986 51.13423260774811, 154.21084299716802 48.19017499759916, 158.9332679602868 42.75764651455549 M149.09238252542917 54.07829021789707 C151.84593396586163 50.91069163316567, 154.5994854062941 47.74309304843426, 158.9332679602868 42.75764651455549 M154.73545696228229 53.68368801296802 C156.05098012122784 52.17035173194947, 157.36650328017342 50.657015450930906, 159.32787016521584 48.400720951408616 M154.73545696228229 53.68368801296802 C156.24479352007694 51.947394921017356, 157.75413007787157 50.211101829066685, 159.32787016521584 48.400720951408616" stroke="#fa5252" stroke-width="0.5" fill="none"></path><path d="M0 0 C42.85518687916917 0, 85.71037375833833 0, 158.9999999999999 0 M0 0 C57.662035526800864 0, 115.32407105360173 0, 158.9999999999999 0 M158.9999999999999 0 C158.9999999999999 16.40436417544261, 158.9999999999999 32.80872835088522, 158.9999999999999 53 M158.9999999999999 0 C158.9999999999999 13.331009528692814, 158.9999999999999 26.662019057385628, 158.9999999999999 53 M158.9999999999999 53 C107.5467047874815 53, 56.093409574963104 53, 0 53 M158.9999999999999 53 C99.94139154357828 53, 40.88278308715668 53, 0 53 M0 53 C0 37.42691702758893, 0 21.853834055177863, 0 0 M0 53 C0 38.142077192012216, 0 23.284154384024436, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1442.0870972286061 1224.701724039657) rotate(0 58 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">without stock</text></g><g transform="translate(63.87281151432046 18.772654820766093) rotate(0 239 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"># create product without stock</text></g><g transform="translate(1402.7656686571772 674.1650017457355) rotate(0 79.5 26.5)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C0.9590294310660872 4.993775187729691, 2.1795156861936227 3.5897663583834936, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.6496073208572388 4.199356200588598, 3.560671465775926 2.000928384101308, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C2.2922858811843985 9.55705143561321, 4.451426381501186 7.073244417297413, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C3.0914745139615354 8.637690081056238, 6.04980364705546 5.234521708183471, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C3.3443144650777965 14.443843336032044, 6.816940373349432 10.449044201059191, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C5.01479641440859 12.522173676688933, 10.157904272011018 6.605704882372967, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C6.313581141842409 17.125105105291176, 12.360871521949596 10.168493302724338, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C4.782279493601126 18.886666143353406, 9.29826822546703 13.6916153788488, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C10.401758796254919 18.519207035371387, 20.798683654836065 6.5589131458088765, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C9.456501407525241 19.606601272058242, 18.90816887737671 8.733701619182579, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C9.005901199992277 26.221969861914648, 18.26842528637223 15.566654781819501, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C7.555575484081738 27.890378745678326, 15.367773854551155 18.903472549346855, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C12.642047587190632 28.136074280874105, 25.14611585583988 13.751789182885304, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C10.608185768210685 30.47576466208169, 21.078392217879987 18.431169945300475, 36.877284942009794 0.25662288638767805 M-0.12347750552006431 48.9181433959388 C14.406384704375723 32.203448948400236, 28.93624691427151 15.488754500861681, 42.520359378862906 -0.13797931854138312 M-0.12347750552006431 48.9181433959388 C9.233749970811559 38.15388452798652, 18.59097744714318 27.389625660034245, 42.520359378862906 -0.13797931854138312 M0.9271837283995019 53.806508252569145 C18.00889372145183 34.15624873525034, 35.090603714504155 14.505989217931528, 47.50737478672552 0.22212805675232872 M0.9271837283995019 53.806508252569145 C17.862422907835555 34.324744131814455, 34.797662087271604 14.842980011059765, 47.50737478672552 0.22212805675232872 M5.914199136262113 54.16661562786285 C23.081586803698528 34.41779522072842, 40.24897447113494 14.668974813593984, 53.15044922357863 -0.1724741481767289 M5.914199136262113 54.16661562786285 C24.35590728671535 32.951857196391245, 42.79761543716859 11.737098764919644, 53.15044922357863 -0.1724741481767289 M11.557273573115229 53.772013422933796 C21.88915933163768 41.886538459312895, 32.22104509016013 30.001063495691994, 58.13746463144125 0.1876332271169865 M11.557273573115229 53.772013422933796 C20.900653777763026 43.023684018852805, 30.244033982410823 32.27535461477181, 58.13746463144125 0.1876332271169865 M16.544288980977836 54.13212079822751 C33.39244654091159 34.750532621397895, 50.24060410084536 15.368944444568285, 63.78053906829436 -0.20696897781207468 M16.544288980977836 54.13212079822751 C30.442759793989424 38.14375906625568, 44.34123060700101 22.15539733428385, 63.78053906829436 -0.20696897781207468 M22.18736341783096 53.73751859329845 C40.118140206275996 33.110519458939486, 58.048916994721026 12.483520324580525, 68.76755447615697 0.1531383974816336 M22.18736341783096 53.73751859329845 C33.500898195362026 40.722785611230535, 44.81443297289309 27.708052629162626, 68.76755447615697 0.1531383974816336 M27.174378825693566 54.09762596859217 C41.51903694549283 37.59598445518877, 55.86369506529209 21.094342941785364, 74.41062891301009 -0.2414638074474169 M27.174378825693566 54.09762596859217 C39.51854700250924 39.89728488456045, 51.86271517932491 25.696943800528732, 74.41062891301009 -0.2414638074474169 M32.817453262546685 53.703023763663104 C49.97093502899642 33.970200265697684, 67.12441679544617 14.237376767732272, 79.3976443208727 0.11864356784629138 M32.817453262546685 53.703023763663104 C45.83650989757114 38.726312318909905, 58.85556653259559 23.749600874156705, 79.3976443208727 0.11864356784629138 M37.80446867040929 54.06313113895682 C50.58084181837462 39.36559511067067, 63.357214966339946 24.66805908238452, 85.04071875772581 -0.27595863708276624 M37.80446867040929 54.06313113895682 C52.652311974553655 36.982641286501135, 67.50015527869802 19.90215143404545, 85.04071875772581 -0.27595863708276624 M43.447543107262405 53.668528934027755 C53.54115053169298 42.0571618380714, 63.63475795612354 30.445794742115048, 90.02773416558841 0.08414873821094204 M43.447543107262405 53.668528934027755 C59.36198264326729 35.36106047317875, 75.27642217927217 17.053592012329744, 90.02773416558841 0.08414873821094204 M48.43455851512502 54.02863630932147 C62.885471912113616 37.40476208193895, 77.33638530910221 20.780887854556426, 95.67080860244155 -0.3104534667181156 M48.43455851512502 54.02863630932147 C61.09681455113109 39.46237700135656, 73.75907058713716 24.896117693391645, 95.67080860244155 -0.3104534667181156 M54.07763295197813 53.63403410439241 C63.76684417702619 42.48787162020596, 73.45605540207424 31.341709136019503, 100.65782401030415 0.049653908575599814 M54.07763295197813 53.63403410439241 C63.522854684102754 42.76854942455894, 72.96807641622738 31.903064744725476, 100.65782401030415 0.049653908575599814 M59.064648359840746 53.99414147968613 C75.20503992215906 35.42674494621858, 91.34543148447739 16.859348412751032, 106.30089844715727 -0.3449482963534578 M59.064648359840746 53.99414147968613 C69.90665639563773 41.52183796446898, 80.74866443143469 29.049534449251826, 106.30089844715727 -0.3449482963534578 M64.70772279669386 53.59953927475706 C81.14042862926009 34.695873639816455, 97.57313446182631 15.792208004875853, 111.28791385501988 0.015159078940250481 M64.70772279669386 53.59953927475706 C77.6778807169985 38.679079366571244, 90.64803863730316 23.758619458385425, 111.28791385501988 0.015159078940250481 M69.69473820455647 53.959646650050786 C83.30804872765351 38.299324306590634, 96.92135925075056 22.639001963130486, 116.2749292628825 0.375266454233973 M69.69473820455647 53.959646650050786 C83.57195224873057 37.9957380333892, 97.44916629290466 22.031829416727625, 116.2749292628825 0.375266454233973 M75.3378126414096 53.56504444512172 C89.05065264842965 37.79022652776953, 102.76349265544968 22.015408610417342, 121.9180036997356 -0.019335750695091747 M75.3378126414096 53.56504444512172 C90.54478350832046 36.07142559029717, 105.75175437523133 18.577806735472613, 121.9180036997356 -0.019335750695091747 M80.3248280492722 53.92515182041544 C96.85611522661567 34.908081320901715, 113.38740240395916 15.891010821388, 126.9050191075982 0.34077162459862365 M80.3248280492722 53.92515182041544 C92.6511138377993 39.745382070916534, 104.97739962632642 25.56561232141764, 126.9050191075982 0.34077162459862365 M85.96790248612533 53.53054961548638 C95.70477304283412 42.32956134184813, 105.44164359954293 31.12857306820987, 132.54809354445132 -0.05383058033042687 M85.96790248612533 53.53054961548638 C102.12242584637285 34.946896308143835, 118.27694920662037 16.363243000801297, 132.54809354445132 -0.05383058033042687 M90.95491789398793 53.89065699078009 C105.38220157030383 37.29396564753089, 119.80948524661974 20.69727430428169, 137.53510895231395 0.3062767949632672 M90.95491789398793 53.89065699078009 C105.5442524583211 37.107547425593715, 120.13358702265427 20.324437860407343, 137.53510895231395 0.3062767949632672 M96.59799233084104 53.49605478585103 C110.83845913987416 37.11427166465995, 125.07892594890727 20.732488543468875, 143.17818338916706 -0.0883254099657762 M96.59799233084104 53.49605478585103 C109.71675322390044 38.40464671258903, 122.83551411695983 23.31323863932702, 143.17818338916706 -0.0883254099657762 M101.58500773870365 53.85616216114475 C111.81690229869126 42.085713913318486, 122.04879685867887 30.315265665492223, 148.16519879702966 0.2717819653279321 M101.58500773870365 53.85616216114475 C116.46409779057373 36.739727037277, 131.3431878424438 19.623291913409247, 148.16519879702966 0.2717819653279321 M107.22808217555678 53.46155995621568 C122.42569725688868 35.97870370154591, 137.6233123382206 18.495847446876148, 153.8082732338828 -0.12282023960112554 M107.22808217555678 53.46155995621568 C121.91485115558635 36.56636491743614, 136.60162013561592 19.6711698786566, 153.8082732338828 -0.12282023960112554 M112.21509758341939 53.8216673315094 C127.60625312960151 36.116168240557066, 142.99740867578362 18.41066914960473, 158.7952886417454 0.23728713569258275 M112.21509758341939 53.8216673315094 C128.57550998385707 35.00116577693906, 144.93592238429474 16.180664222368712, 158.7952886417454 0.23728713569258275 M117.20211299128198 54.181774706803104 C127.5022841883169 42.33278317276633, 137.80245538535183 30.483791638729556, 159.18989084667447 5.880361572545695 M117.20211299128198 54.181774706803104 C132.9196815579222 36.10078038941022, 148.6372501245624 18.019786072017332, 159.18989084667447 5.880361572545695 M122.8451874281351 53.78717250187405 C136.21592740610657 38.40589565004875, 149.586667384078 23.02461879822345, 158.928434022613 12.278145589621587 M122.8451874281351 53.78717250187405 C136.1507215140126 38.48090644827832, 149.45625559989006 23.17464039468259, 158.928434022613 12.278145589621587 M127.83220283599772 54.14727987716777 C139.49335374182792 40.73266028326407, 151.1545046476581 27.31804068936036, 159.32303622754208 17.921220026474714 M127.83220283599772 54.14727987716777 C134.99547975648431 45.90687241566457, 142.15875667697094 37.66646495416138, 159.32303622754208 17.921220026474714 M133.47527727285083 53.752677672238704 C139.90777337582978 46.35293737579948, 146.3402694788087 38.95319707936025, 159.0615794034806 24.319004043550592 M133.47527727285083 53.752677672238704 C141.77271026596918 44.2075728959221, 150.0701432590875 34.6624681196055, 159.0615794034806 24.319004043550592 M138.46229268071346 54.11278504753242 C143.373776160389 48.46276961992574, 148.2852596400646 42.81275419231905, 158.80012257941917 30.716788060626484 M138.46229268071346 54.11278504753242 C146.30494626051942 45.090844140544895, 154.14759984032534 36.06890323355738, 158.80012257941917 30.716788060626484 M144.10536711756657 53.718182842603355 C149.64530062640395 47.34521835593179, 155.18523413524136 40.97225386926022, 159.19472478434824 36.3598624974796 M144.10536711756657 53.718182842603355 C148.06447503732974 49.16375017092931, 152.0235829570929 44.60931749925527, 159.19472478434824 36.3598624974796 M149.09238252542917 54.07829021789707 C152.35916932678035 50.32028188849612, 155.62595612813152 46.56227355909516, 158.9332679602868 42.75764651455549 M149.09238252542917 54.07829021789707 C151.07904965559007 51.79289111569554, 153.065716785751 49.507492013494, 158.9332679602868 42.75764651455549 M154.73545696228229 53.68368801296802 C156.08904198267132 52.12656656902486, 157.44262700306038 50.5694451250817, 159.32787016521584 48.400720951408616 M154.73545696228229 53.68368801296802 C155.7443932571591 52.523039574443125, 156.7533295520359 51.36239113591823, 159.32787016521584 48.400720951408616" stroke="#fa5252" stroke-width="0.5" fill="none"></path><path d="M0 0 C57.12026438964527 0, 114.24052877929054 0, 158.9999999999999 0 M0 0 C46.70137843983245 0, 93.4027568796649 0, 158.9999999999999 0 M158.9999999999999 0 C158.9999999999999 19.07754825735465, 158.9999999999999 38.1550965147093, 158.9999999999999 53 M158.9999999999999 0 C158.9999999999999 20.238926912005994, 158.9999999999999 40.47785382401199, 158.9999999999999 53 M158.9999999999999 53 C100.32112446175881 53, 41.64224892351773 53, 0 53 M158.9999999999999 53 C120.11725420458234 53, 81.23450840916479 53, 0 53 M0 53 C0 37.942913892026986, 0 22.885827784053976, 0 0 M0 53 C0 32.091631084028634, 0 11.183262168057261, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1432.7656686571772 689.1650017457355) rotate(0 58 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">without stock</text></g><g transform="translate(955.0750205101397 10) rotate(0 363 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"># creating product with stock: unknown restock</text></g><g transform="translate(949.3607347958546 1107.5000000000002) rotate(0 388 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"># creating product with stock: with restock never </text></g><g transform="translate(944.3607347958537 557.9401274238317) rotate(0 328 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"># creating product next restock: with date</text></g><g transform="translate(1164.0591474942667 1281.4486080177874) rotate(0 49.370370370370324 25)"><path d="M0 0 C23.45212747769911 0, 46.90425495539822 0, 98.74074074074065 0 M0 0 C20.73102883723459 0, 41.46205767446918 0, 98.74074074074065 0 M98.74074074074065 0 C98.74074074074065 15.249146842397751, 98.74074074074065 30.498293684795502, 98.74074074074065 50 M98.74074074074065 0 C98.74074074074065 16.16197635885328, 98.74074074074065 32.32395271770656, 98.74074074074065 50 M98.74074074074065 50 C60.310699718686934 50, 21.88065869663322 50, 0 50 M98.74074074074065 50 C76.67712927301304 50, 54.613517805285426 50, 0 50 M0 50 C0 36.00903776939958, 0 22.018075538799163, 0 0 M0 50 C0 36.17254475597292, 0 22.345089511945844, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1199.6517400868593 1294.9486080177874) rotate(0 11 11.5)"><text x="11" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">15</text></g><g transform="translate(1164.5591474942662 741.9486080177871) rotate(0 49.370370370370324 25)"><path d="M0 0 C36.75340074836791 0, 73.50680149673582 0, 98.74074074074065 0 M0 0 C27.905231700830686 0, 55.81046340166137 0, 98.74074074074065 0 M98.74074074074065 0 C98.74074074074065 10.219821208156645, 98.74074074074065 20.43964241631329, 98.74074074074065 50 M98.74074074074065 0 C98.74074074074065 19.624865702353418, 98.74074074074065 39.249731404706836, 98.74074074074065 50 M98.74074074074065 50 C63.61054871782516 50, 28.480356694909673 50, 0 50 M98.74074074074065 50 C59.59350222807924 50, 20.446263715417828 50, 0 50 M0 50 C0 37.69948286470026, 0 25.398965729400512, 0 0 M0 50 C0 35.27201617602259, 0 20.54403235204518, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1200.1517400868588 755.4486080177871) rotate(0 11 11.5)"><text x="11" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">15</text></g><g transform="translate(1814.0809814929971 1842.1071341952047) rotate(0 412 266.56944444444457)"><path d="M0 0 C274.16651551425457 0, 548.3330310285091 0, 824 0 M0 0 C297.1355347424746 0, 594.2710694849492 0, 824 0 M824 0 C824 116.17392364551009, 824 232.34784729102017, 824 533.1388888888891 M824 0 C824 179.31330792878038, 824 358.62661585756075, 824 533.1388888888891 M824 533.1388888888891 C567.5864898949861 533.1388888888891, 311.17297978997226 533.1388888888891, 0 533.1388888888891 M824 533.1388888888891 C609.0388737887145 533.1388888888891, 394.0777475774288 533.1388888888891, 0 533.1388888888891 M0 533.1388888888891 C0 356.3190921438136, 0 179.49929539873796, 0 0 M0 533.1388888888891 C0 424.3866610642214, 0 315.6344332395537, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1907.0809814929967 1912.1071341952047) rotate(0 25 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Stock</text></g><g transform="translate(1941.4976481596632 1976.507927845998) rotate(0 31 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">current</text></g><g transform="translate(1892.9034923155082 2261.8565711090932) rotate(0 288.5 28.5)"><path d="M0 0 C210.84164893589912 0, 421.68329787179823 0, 576.9999999999999 0 M0 0 C226.9310409609228 0, 453.8620819218456 0, 576.9999999999999 0 M576.9999999999999 0 C576.9999999999999 18.367664065584542, 576.9999999999999 36.735328131169084, 576.9999999999999 57 M576.9999999999999 0 C576.9999999999999 15.9439185295254, 576.9999999999999 31.8878370590508, 576.9999999999999 57 M576.9999999999999 57 C425.9349190238862 57, 274.8698380477726 57, 0 57 M576.9999999999999 57 C374.58122126422813 57, 172.16244252845638 57, 0 57 M0 57 C0 42.26120472885668, 0 27.522409457713366, 0 0 M0 57 C0 40.81852394007146, 0 24.637047880142923, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2387.903492315508 2261.8565711090932) rotate(0 41 29)"><path d="M0 0 C25.642520541697746 0, 51.28504108339549 0, 82 0 M0 0 C26.927581327408557 0, 53.855162654817114 0, 82 0 M82 0 C82 13.545655617862941, 82 27.091311235725883, 82 58 M82 0 C82 15.152590277045967, 82 30.305180554091933, 82 58 M82 58 C58.220881395787 58, 34.441762791574 58, 0 58 M82 58 C60.07624772265554 58, 38.15249544531107 58, 0 58 M0 58 C0 41.12247482761741, 0 24.244949655234812, 0 0 M0 58 C0 44.12997278943658, 0 30.259945578873158, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(2426.903492315508 2273.8565711090932) rotate(0 0 17)"><path d="M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34 M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2426.903492315508 2273.8565711090932) rotate(0 0 17)"><path d="M-5.814342436536368 18.025225446639556 C-4.643740285856778 21.241428422796748, -3.4731381351771877 24.45763139895394, 0 34 M-5.814342436536368 18.025225446639556 C-4.192122791573714 22.482237290570144, -2.5699031466110593 26.939249134500734, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2426.903492315508 2273.8565711090932) rotate(0 0 17)"><path d="M5.814342436536368 18.025225446639556 C4.643740285856778 21.241428422796748, 3.4731381351771877 24.45763139895394, 0 34 M5.814342436536368 18.025225446639556 C4.192122791573714 22.482237290570144, 2.5699031466110593 26.939249134500734, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(1923.8894077379477 2277.8565711090932) rotate(0 35.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">address</text></g><g transform="translate(2122.486963969733 1971.636797748869) rotate(0 11 11.5)"><text x="11" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">15</text></g><g transform="translate(1943.9162053758716 2213.340383000729) rotate(0 54 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">next restock</text></g><g transform="translate(2298.630491090157 2204.5546687150145) rotate(0 36 23)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.2611187238108525 4.646261209196374, 2.7836942716831534 2.8947384013168596, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.684746007607977 4.158933765479314, 3.6309488392774023 1.920083513882739, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C3.739643965731985 7.892056421213751, 7.346142550596359 3.743254388498496, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C2.495653567887535 9.3231036737803, 4.858161754907459 6.605348893631596, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C4.036540063134039 13.647528877358473, 8.201391569461917 8.85641528371205, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C4.724114151797874 12.856565368135819, 9.576539746789587 7.274488265266742, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C5.662661821618544 17.873902126926485, 11.059032881501865 11.666087345994956, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C8.512157091179688 14.59593279229763, 16.758023420624156 5.110148676737246, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C5.41527874113689 24.255496154016846, 10.825723544600008 18.031491383099794, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C9.2384643851211 19.857424174236503, 18.472094832568427 9.235347423539103, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C6.6630249272410005 28.91714070811543, 13.582672740869679 20.956996474221064, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C6.85865783887235 28.692090787162066, 13.973938564132379 20.506896632314337, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C12.757833347695543 28.0028779999832, 25.377687376849703 13.485396621103487, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C9.781914135509359 31.42628144412422, 19.425848952477335 20.332203509385533, 36.877284942009794 0.25662288638767805 M1.1886405524609494 47.40872423549325 C15.385556051510763 31.07704116540005, 29.582471550560577 14.745358095306848, 42.520359378862906 -0.13797931854138312 M1.1886405524609494 47.40872423549325 C10.468500563770826 36.73346645504877, 19.748360575080703 26.058208674604284, 42.520359378862906 -0.13797931854138312 M6.831714989314069 47.014122030564195 C23.047288933632743 28.36023806006382, 39.26286287795142 9.706354089563447, 47.50737478672552 0.22212805675232872 M6.831714989314069 47.014122030564195 C15.250952012991574 37.328897745620154, 23.67018903666908 27.643673460676105, 47.50737478672552 0.22212805675232872 M11.818730397176676 47.3742294058579 C22.597903379623546 34.974209350880756, 33.37707636207041 22.574189295903615, 53.15044922357863 -0.1724741481767289 M11.818730397176676 47.3742294058579 C25.14197529521831 32.047589393482305, 38.46522019325994 16.72094938110671, 53.15044922357863 -0.1724741481767289 M17.461804834029795 46.979627200928846 C33.226246254203865 28.844711833674296, 48.99068767437794 10.709796466419746, 58.13746463144125 0.1876332271169865 M17.461804834029795 46.979627200928846 C32.04277050544074 30.20614494576362, 46.62373617685169 13.432662690598391, 58.13746463144125 0.1876332271169865 M22.448820241892403 47.33973457622256 C34.020553773428105 34.02797790476389, 45.592287304963804 20.71622123330521, 63.78053906829436 -0.20696897781207468 M22.448820241892403 47.33973457622256 C32.413442208827774 35.87674827555963, 42.37806417576315 24.413761974896698, 63.78053906829436 -0.20696897781207468 M28.091894678745525 46.9451323712935 C37.03616338094111 36.65592823059203, 45.9804320831367 26.36672408989057, 68.76755447615697 0.1531383974816336 M28.091894678745525 46.9451323712935 C40.145889213497476 33.07859787770013, 52.199883748249434 19.212063384106777, 68.76755447615697 0.1531383974816336 M33.07891008660813 47.30523974658722 C41.38525638927088 37.749881380566954, 49.691602691933625 28.19452301454669, 73.09851085502908 1.2679553529981291 M33.07891008660813 47.30523974658722 C45.61547031299049 32.88357692693349, 58.152030539372845 18.461914107279764, 73.09851085502908 1.2679553529981291 M38.72198452346125 46.91063754165816 C49.12053993799855 34.948467912037486, 59.51909535253584 22.986298282416808, 73.49311305995813 6.911029789851241 M38.72198452346125 46.91063754165816 C45.893685857880584 38.66053890051741, 53.065387192299916 30.41044025937665, 73.49311305995813 6.911029789851241 M43.70899993132386 47.27074491695187 C53.860181013368766 35.593146904187826, 64.01136209541367 23.91554889142378, 73.23165623589668 13.30881380692713 M43.70899993132386 47.27074491695187 C51.905471129667134 37.841783399680835, 60.10194232801041 28.412821882409805, 73.23165623589668 13.30881380692713 M49.35207436817697 46.87614271202281 C56.96246633493155 38.12138822689979, 64.57285830168613 29.366633741776763, 72.97019941183524 19.706597824003016 M49.35207436817697 46.87614271202281 C55.967382671880934 39.26610103541496, 62.5826909755849 31.656059358807116, 72.97019941183524 19.706597824003016 M54.339089776039586 47.23625008731652 C59.720999826929734 41.045070794267275, 65.10290987781988 34.85389150121803, 73.3648016167643 25.34967226085613 M54.339089776039586 47.23625008731652 C59.65157792303411 41.12493155927794, 64.96406607002864 35.01361303123936, 73.3648016167643 25.34967226085613 M59.9821642128927 46.84164788238747 C63.66028229464649 42.610457043109555, 67.33840037640029 38.37926620383165, 73.10334479270284 31.747456277932027 M59.9821642128927 46.84164788238747 C64.12857415865852 42.07174887739148, 68.27498410442436 37.30184987239548, 73.10334479270284 31.747456277932027 M64.96917962075531 47.20175525768118 C67.63395468548822 44.13628221086212, 70.29872975022114 41.070809164043055, 73.49794699763191 37.39053071478514 M64.96917962075531 47.20175525768118 C67.26606697808306 44.55948860686598, 69.56295433541081 41.91722195605079, 73.49794699763191 37.39053071478514 M69.95619502861793 47.561862632974886 C70.80251865776677 46.58827866771744, 71.6488422869156 45.614694702459985, 73.23649017357046 43.78831473186103 M69.95619502861793 47.561862632974886 C71.0006149851761 46.36039491107923, 72.04503494173426 45.15892718918357, 73.23649017357046 43.78831473186103" stroke="#4c6ef5" stroke-width="0.5" fill="none"></path><path d="M0 0 C16.193762657046317 0, 32.387525314092635 0, 72 0 M0 0 C17.504456117749214 0, 35.00891223549843 0, 72 0 M72 0 C72 18.31221368983388, 72 36.62442737966776, 72 46 M72 0 C72 9.369684558361769, 72 18.739369116723537, 72 46 M72 46 C56.27316487133503 46, 40.54632974267005 46, 0 46 M72 46 C54.11647951304913 46, 36.23295902609825 46, 0 46 M0 46 C0 29.97982518002391, 0 13.959650360047817, 0 0 M0 46 C0 28.27324437573552, 0 10.546488751471038, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(25.09190430596891 1844.8671778767057) rotate(0 412 84.5)"><path d="M0 0 C167.83794610202312 0, 335.67589220404625 0, 824 0 M0 0 C257.2014637738466 0, 514.4029275476933 0, 824 0 M824 0 C824 50.912549302354456, 824 101.82509860470891, 824 169 M824 0 C824 65.41591384075582, 824 130.83182768151164, 824 169 M824 169 C620.7830524712801 169, 417.5661049425602 169, 0 169 M824 169 C523.9873734682799 169, 223.97474693655965 169, 0 169 M0 169 C0 129.2093227174133, 0 89.41864543482662, 0 0 M0 169 C0 116.37540726996957, 0 63.75081453993916, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(118.09190430596891 1914.8671778767057) rotate(0 25 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Stock</text></g><g transform="translate(210.0919043059689 1900.1206990210958) rotate(0 57.125 26.5)"><path d="M0 0 C35.751818736735736 0, 71.50363747347147 0, 114.25 0 M0 0 C23.568781670089813 0, 47.137563340179625 0, 114.25 0 M114.25 0 C114.25 13.111394657567145, 114.25 26.22278931513429, 114.25 53 M114.25 0 C114.25 20.921167401596904, 114.25 41.84233480319381, 114.25 53 M114.25 53 C85.3933772421442 53, 56.536754484288394 53, 0 53 M114.25 53 C70.957347367052 53, 27.664694734103975 53, 0 53 M0 53 C0 40.39483490996063, 0 27.789669819921254, 0 0 M0 53 C0 38.70905513353645, 0 24.41811026707291, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(238.0919043059689 1915.1206990210958) rotate(0 29 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">infinite</text></g><g transform="translate(41.46471582028926 1777.6935835477643) rotate(0 328 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"># updating product: product without stock</text></g><g transform="translate(1940.5139130676002 2023.2022267517714) rotate(0 40 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">incoming</text></g><g transform="translate(2127.00322887767 2024.3310966546414) rotate(0 5.5 11.5)"><text x="5.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">0</text></g><g transform="translate(1940.5139130676002 2074.2022267517714) rotate(0 42 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">notify lost</text></g><g transform="translate(2127.00322887767 2081.3310966546414) rotate(0 5.5 11.5)"><text x="5.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">0</text></g><g transform="translate(1940.5139130676002 2138.2022267517714) rotate(0 53.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">after update</text></g><g transform="translate(2127.50322887767 2139.3310966546414) rotate(0 11 11.5)"><text x="11" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">15</text></g><g transform="translate(2093.0085709726354 2013.2666617032064) rotate(0 52.5 20.5)"><path d="M0 0 C29.524161050096158 0, 59.048322100192316 0, 105 0 M0 0 C36.504488250240684 0, 73.00897650048137 0, 105 0 M105 0 C105 10.325107226148248, 105 20.650214452296495, 105 41 M105 0 C105 9.495934232696891, 105 18.991868465393782, 105 41 M105 41 C74.71515481732786 41, 44.43030963465571 41, 0 41 M105 41 C82.80356870032847 41, 60.60713740065694 41, 0 41 M0 41 C0 29.32805828116834, 0 17.65611656233668, 0 0 M0 41 C0 30.19957923032343, 0 19.399158460646863, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2094.0085709726354 2070.2666617032064) rotate(0 51 22.5)"><path d="M0 0 C29.419563891738658 0, 58.839127783477316 0, 102 0 M0 0 C21.562247548252344 0, 43.12449509650469 0, 102 0 M102 0 C102 12.810667740181088, 102 25.621335480362177, 102 45 M102 0 C102 11.854120356962087, 102 23.708240713924173, 102 45 M102 45 C80.61069051995874 45, 59.22138103991747 45, 0 45 M102 45 C80.83884798511863 45, 59.67769597023725 45, 0 45 M0 45 C0 28.328645361587405, 0 11.65729072317481, 0 0 M0 45 C0 34.01418258436024, 0 23.028365168720484, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2315.630491090157 2215.0546687150145) rotate(0 21.5 11.5)"><text x="21.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">clear</text></g><g transform="translate(2398.813380718231 2204.477938912777) rotate(0 36 23)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.2929012427776867 4.6096996034750255, 2.8472593096168217 2.8216151898741626, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C0.8517481006590948 5.117188240914534, 1.964953025379638 3.836592464753179, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C4.09839555532937 7.479359926500602, 8.06364572979113 2.9178613990721978, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C3.417184224681352 8.263003919919068, 6.701223068495093 4.4851493859091285, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C4.626918667928739 12.968375982103431, 9.382148779051317 7.498109493201968, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C4.0565887613896 13.62446548827937, 8.241488965973039 8.81028850555384, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C5.715422844976365 17.813207512523, 11.164554928217507 11.544698117187984, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C5.3614574419609475 18.220398129401186, 10.456624122186673 12.35907935094436, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C7.255578161251454 22.13847384128991, 14.506322384829135 13.797446757645918, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C9.11980589185277 19.993925156140836, 18.23477784603177 9.50834938734777, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C9.516160549036586 25.634983627284917, 19.28894398446085 14.392682312560037, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C8.576053189518198 26.716453433070832, 17.408729265424075 16.555621924131874, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C7.888108409659516 33.60485572055613, 15.638237500777649 24.689352062249355, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C10.083295149170755 31.079582247471905, 20.028610979800128 19.638805116080903, 36.877284942009794 0.25662288638767805 M1.1886405524609494 47.40872423549325 C12.453225116675018 34.45030203235194, 23.717809680889086 21.491879829210635, 42.520359378862906 -0.13797931854138312 M1.1886405524609494 47.40872423549325 C17.347384032036103 28.820216236201507, 33.506127511611254 10.23170823690976, 42.520359378862906 -0.13797931854138312 M6.831714989314069 47.014122030564195 C21.55381318289163 30.078285380667076, 36.27591137646919 13.142448730769956, 47.50737478672552 0.22212805675232872 M6.831714989314069 47.014122030564195 C17.43780191320385 34.813214709081535, 28.043888837093625 22.61230738759887, 47.50737478672552 0.22212805675232872 M11.818730397176676 47.3742294058579 C21.766510546829146 35.93061739971741, 31.71429069648162 24.487005393576922, 53.15044922357863 -0.1724741481767289 M11.818730397176676 47.3742294058579 C25.628588071527656 31.48780542906593, 39.43844574587864 15.601381452273955, 53.15044922357863 -0.1724741481767289 M17.461804834029795 46.979627200928846 C31.670289547372953 30.63463527221622, 45.87877426071611 14.289643343503592, 58.13746463144125 0.1876332271169865 M17.461804834029795 46.979627200928846 C27.76486623666902 35.1273108656745, 38.06792763930825 23.274994530420155, 58.13746463144125 0.1876332271169865 M22.448820241892403 47.33973457622256 C34.76571105880082 33.170772505260544, 47.08260187570924 19.001810434298527, 63.78053906829436 -0.20696897781207468 M22.448820241892403 47.33973457622256 C35.18121105421159 32.69279443733952, 47.91360186653077 18.045854298456483, 63.78053906829436 -0.20696897781207468 M28.091894678745525 46.9451323712935 C38.55263945950966 34.91142205950037, 49.01338424027381 22.87771174770723, 68.76755447615697 0.1531383974816336 M28.091894678745525 46.9451323712935 C44.16297574114715 28.457468447218805, 60.23405680354878 9.969804523144113, 68.76755447615697 0.1531383974816336 M33.07891008660813 47.30523974658722 C43.00925016649015 35.8816902457304, 52.939590246372155 24.458140744873575, 73.09851085502908 1.2679553529981291 M33.07891008660813 47.30523974658722 C44.183068593544675 34.53136661143301, 55.28722710048122 21.757493476278793, 73.09851085502908 1.2679553529981291 M38.72198452346125 46.91063754165816 C50.32497873871401 33.56291956726326, 61.92797295396676 20.215201592868357, 73.49311305995813 6.911029789851241 M38.72198452346125 46.91063754165816 C50.67816756563262 33.15662229899264, 62.63435060780398 19.402607056327117, 73.49311305995813 6.911029789851241 M43.70899993132386 47.27074491695187 C52.82528990392236 36.783652941408874, 61.94157987652086 26.296560965865872, 73.23165623589668 13.30881380692713 M43.70899993132386 47.27074491695187 C51.6217935531243 38.168117121572735, 59.53458717492474 29.065489326193596, 73.23165623589668 13.30881380692713 M49.35207436817697 46.87614271202281 C56.227503305490856 38.9668664764438, 63.10293224280475 31.057590240864783, 72.97019941183524 19.706597824003016 M49.35207436817697 46.87614271202281 C58.04774158782605 36.87292186283115, 66.74340880747513 26.869701013639492, 72.97019941183524 19.706597824003016 M54.339089776039586 47.23625008731652 C58.367247243970056 42.602384996897925, 62.39540471190053 37.96851990647933, 73.3648016167643 25.34967226085613 M54.339089776039586 47.23625008731652 C59.4060130110888 41.40742167590182, 64.47293624613802 35.57859326448713, 73.3648016167643 25.34967226085613 M59.9821642128927 46.84164788238747 C62.6812477262444 43.736707480176584, 65.3803312395961 40.63176707796569, 73.10334479270284 31.747456277932027 M59.9821642128927 46.84164788238747 C63.23149924957844 43.10371551170787, 66.48083428626418 39.36578314102827, 73.10334479270284 31.747456277932027 M64.96917962075531 47.20175525768118 C67.55133689041521 44.23132311218837, 70.13349416007512 41.26089096669556, 73.49794699763191 37.39053071478514 M64.96917962075531 47.20175525768118 C67.69743126289549 44.06326076161429, 70.42568290503566 40.92476626554739, 73.49794699763191 37.39053071478514 M69.95619502861793 47.561862632974886 C70.67077826831753 46.739828649694815, 71.38536150801714 45.91779466641475, 73.23649017357046 43.78831473186103 M69.95619502861793 47.561862632974886 C71.17890829205336 46.15529192362867, 72.40162155548879 44.74872121428245, 73.23649017357046 43.78831473186103" stroke="#4c6ef5" stroke-width="0.5" fill="none"></path><path d="M0 0 C21.932444740086794 0, 43.86488948017359 0, 72 0 M0 0 C16.67752176448703 0, 33.35504352897406 0, 72 0 M72 0 C72 15.75052264314145, 72 31.5010452862829, 72 46 M72 0 C72 17.814064511843025, 72 35.62812902368605, 72 46 M72 46 C55.68650033399463 46, 39.37300066798925 46, 0 46 M72 46 C54.943963611871 46, 37.887927223742004 46, 0 46 M0 46 C0 35.37932818550617, 0 24.75865637101233, 0 0 M0 46 C0 32.96904833596199, 0 19.93809667192399, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2407.313380718231 2214.977938912777) rotate(0 25 11.5)"><text x="25" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">never</text></g><g transform="translate(2079.7394011263946 2209.0074728050386) rotate(0 71.39795918367349 18.459183673469397)"><path d="M-0.5332256704568863 0.6636613756418228 L142.39418197377609 -0.21745406091213226 L142.0709440778105 37.68443713169921 L-1.0454198271036148 37.45789322834838" stroke="none" stroke-width="0" fill="#fff"></path><path d="M1.2337845712900162 0.015040740370750427 C28.56659816368199 -0.6406339541427333, 60.50770338205053 0.5121108159073156, 142.37637738092826 0.3370445817708969 M0.969361238181591 0.0363282635807991 C53.000192554431926 -1.0081881181698065, 105.90986145613148 -1.295944322774909, 143.62886483921693 -0.8408563658595085 M144.35668972834037 -0.005633488297462463 C143.05124262072758 7.868321860368756, 144.06162193515019 15.354444567433411, 143.8131206403582 38.28928787093986 M142.8561464096515 -0.7321699187159538 C142.48485237584282 9.912379578227283, 143.74567300305534 21.5151276225338, 141.94549305691407 36.03820743989576 M143.7820804487078 35.948196714934 C103.69038879167367 34.684089546974484, 62.7665590731161 37.91535604554016, 0.4336971193552017 35.91201574188102 M143.5466149593799 37.79356136750806 C111.85944364060252 36.627684100235264, 80.07601225102437 37.33753226574735, -0.7850254252552986 36.95606484841932 M1.762398138642311 37.63891774993766 C1.6323946739687605 28.70091673362313, -1.345415708874257 16.862387763207035, 0.34800995886325836 -1.2112757116556168 M0.9106399342417717 36.41863313150037 C-0.325401134167095 27.893693413798267, -0.25188214269675807 20.403612399709445, -0.8587933257222176 -0.8126259371638298" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2114.387360310068 2215.4666564785084) rotate(0 5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(2144.887360310068 2214.9666564785084) rotate(0 5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(2233.887360310068 2207.9666564785084) rotate(0 17.75 17.75)"><path d="M-0.21745406091213226 -0.7249742895364761 L36.266069784760475 -1.0454198271036148 L36.039525881409645 34.953821524977684 L-0.5811678022146225 33.94901929795742" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-1.6772920042276382 -0.5623360723257065 C12.31542037986219 -0.07014615889638665, 26.016979809850454 1.8284014904871584, 36.63062797486782 0.5429748445749283 M-0.6205151602625847 -0.8873010352253914 C13.182961030676962 0.9743744572624564, 27.34160842522979 -0.8362084189429879, 36.01312632113695 -0.8793523982167244 M35.90208564698696 1.0762657076120377 C35.920972196497026 14.437571438774468, 36.869920579828324 26.54535238966346, 36.92520032823086 35.345044031739235 M34.882127709686756 0.6866742894053459 C35.69470356430858 10.01338423974812, 34.359919771812855 21.528746228665113, 35.70761031657457 35.05759137123823 M33.8974636644125 35.468544855713844 C24.72829246856272 36.09227961298078, 9.692773006111384 34.0602547525987, -0.8783871084451675 34.875888243317604 M35.65491981059313 35.63417714089155 C23.049795074388385 34.88912582490593, 8.907751698046923 35.3702452192083, 0.15197987109422684 35.72035758942366 M1.736088141798973 34.21069277822971 C-0.2767997700348496 22.069753262773155, -1.3391734081879259 6.453609279543162, -1.8685132414102554 0.9973238855600357 M-0.6993556544184685 34.90320556610823 C0.31328725669533014 20.75843490771949, -0.6352202906832098 7.467843631654976, 0.3318306878209114 -0.20086819678544998" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2234.887360310068 2208.9666564785084) rotate(0 17.5 4.5)"><path d="M-0.7249742895364761 0.7660697847604752 L33.954580172896385 0.5395258814096451 L34.453821524977684 8.418832197785378 L-1.5509807020425797 9.610531702637672" stroke="none" stroke-width="0" fill="#000"></path><path d="M-0.5623360723257065 -0.5245472341775894 C10.10678030923009 0.6305706825107336, 22.531649254262447 1.4241540756076574, 35.54297484457493 1.938722476363182 M-0.8873010352253914 -0.9082713648676872 C11.460095394402742 -0.6236760597676039, 20.276661440730095 0.7303066272288561, 34.120647601783276 0.7803856804966927 M35.48431956842542 0.18988746330142015 C35.46070591054857 3.314379166066647, 34.870041213855146 6.03627000823617, 34.93026981428265 9.054205238074065 M35.30900343023241 0.20458074845373636 C34.56563543990254 1.6449751149863008, 34.85883403733373 4.175518788769842, 34.800916117057206 9.221886468306185 M34.968544855713844 10.628730162978172 C26.631495725363493 7.713204536214471, 15.797269470989704 7.84116903282702, -0.6241117566823959 10.501393184065819 M35.13417714089155 9.864767976105213 C20.651795502752066 9.091919435188174, 7.569735825061798 9.206201804801822, 0.22035758942365646 9.881199069321156 M-0.580188249796629 8.932994066923857 C0.0806218392401934 5.4306782484054565, -0.7464274399727583 2.1106736786663536, 0.4487957485020161 0.8195759408175946 M-0.26855749525129796 9.06114672459662 C-0.326128788292408 6.384079122170806, -0.05964756757020948 4.6488453973084685, -0.0903906885534525 -0.04892716370522976" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2242.387360310068 2200.4666564785084) rotate(0 3 7)"><path d="M0.7660697847604752 -1.0454198271036148 L6.539525881409645 -0.546178475022316 L5.4188321977853775 12.44901929795742 L0.6105317026376724 12.975818023085594" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-0.1573641702532768 -0.1258622959256172 C1.3105869054794312 0.4605720810592175, 2.7581354543566703 0.1797625355422497, 6.581616742908954 0.021796958148479484 M-0.27248140946030613 0.24988394156098365 C1.308709875494242 -0.24005285918712616, 3.2758714668452744 -0.2105676573514938, 6.234115704149008 -0.0008450232446193806 M6.295380498468876 0.712041591107845 C6.987790362089871 4.039350315928459, 7.0257862250506875 8.383771772682667, 6.084319259226322 12.974962113797664 M6.318236719816923 -0.5952977173030376 C5.297385944426059 3.2569841168820863, 6.058825100958347 6.482704214006663, 6.345156728476286 13.660440278798342 M6.488619048893452 14.13010913580656 C3.6300677686929705 13.51955802336335, 1.6004303678870209 13.811822818666696, 0.4504179552197457 14.525116412341594 M6.259430392831564 13.76449237242341 C3.9169691093266006 13.916878819167614, 1.856913679093122 14.07415790528059, 0.2643597207963467 14.108082560449839 M-0.10423145145177837 14.243606971204281 C-0.9694191680848598 7.575133657455444, -1.4294854389131069 3.9342222943902008, 1.2748959079384803 -0.6996279016137122 M0.09511712715029719 13.398844671994448 C-0.4709283643960952 10.551809810847045, 0.3301912730932236 7.336269853264093, -0.07610892131924629 -0.2537410013377666" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2257.387360310068 2200.4666564785084) rotate(0 3 7)"><path d="M-1.0454198271036148 0.5395258814096451 L5.453821524977684 -0.5811678022146225 L4.44901929795742 14.610531702637672 L-1.0241819769144058 15.71179236471653" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-0.1258622959256172 0.10111337453126912 C1.7405143976211548 0.35492480948567384, 2.7565172508358957 0.5973531599342823, 6.02179695814848 -0.23903321474790573 M0.24988394156098365 -0.25225690975785253 C1.1343999825417996 0.20843417823314664, 2.591576088219881 0.288611986041069, 5.9991549767553805 0.009882958978414513 M6.712041591107845 0.9596443668007848 C5.8685684402287 5.4791001826524734, 5.966869421750307 9.047239165008069, 4.974962113797664 13.19619512706995 M5.404702282696962 -0.6161119349300861 C5.9569233903288845 3.4803060151636602, 5.786448360383511 7.015114315599203, 5.660440278798342 14.312697874754667 M6.130109135806561 13.698094518482685 C4.201262578368187 13.785345772355795, 3.1742882743477816 14.49927986010909, 0.5251164123415947 14.294340141117573 M5.76449237242341 14.011309250444175 C4.015876304358243 14.097480039894581, 2.2802035041153426 14.316245799362658, 0.10808256044983866 14.25327547416091 M0.24360697120428076 13.152107001841069 C-0.9526626242697239 7.276779031753539, 0.7883782254159449 4.444372509419917, -0.6996279016137122 -0.9384387955069542 M-0.6011553280055523 13.431161843985318 C-0.10307776391506192 11.011379397660493, -0.05705651700496668 7.482086911052464, -0.2537410013377666 0.26812442466616626" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(2250.887360310068 2216.9666564785084) rotate(0 0.20799543491568784 12.861703209578991)"><path d="M0.3370445817708969 1.4790066629648209 C1.1970670645311474 7.748928401209415, 2.141103164218366 14.483514787964525, -0.2967773824930191 25.25896967947483 M-0.8408563658595085 -0.9776364043354988 C0.3780693576857448 4.715135126076639, 0.7509636652842164 11.190323036797345, 0.5329431965947151 26.70104282349348" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(2241.387360310068 2215.9666564785084) rotate(0 0.250685129314661 14.525629587471485)"><path d="M1.4790066629648209 1.1306279748678207 C0.6211254256218672 9.60351373706013, 0.28769342735409736 14.533647750355303, -0.7410303205251694 26.225397929549217 M-0.9776364043354988 0.5131263211369514 C-0.5415409543365239 6.641430140696466, 0.43958113148808486 11.750827835164964, 0.7010428234934807 28.53813285380602" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(2260.887360310068 2217.4666564785084) rotate(0 0.881765391677618 12.415816836059093)"><path d="M1.1306279748678207 0.5429748445749283 C2.400230086557567 7.176649219505489, 0.08326465371996172 12.978047614134848, -0.2746020704507828 23.683457270264626 M0.5131263211369514 -0.8793523982167244 C1.14090927798301 9.785861305184664, 0.9684087648615243 19.763734376095236, 2.038132853806019 25.71098607033491" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(2269.887360310068 2225.4666564785084) rotate(0 -17.636783942580223 0.7824612371146031)"><path d="M0.5429748445749283 1.938722476363182 C-10.700319261848927 -0.6045706267654896, -22.78698189854622 -1.5823953147232532, -35.816542729735374 1.665892943739891 M-0.8793523982167244 0.7803856804966927 C-7.343905100226403 0.20740614578127864, -14.481133888661862 0.7125958029925823, -33.78901392966509 0.5086011365056038" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(2269.387360310068 2234.4666564785084) rotate(0 -16.776338193565607 0.44000930051925025)"><path d="M1.938722476363182 0.0726565271615982 C-14.25333623595536 -0.7693445153534413, -28.6933729172498 -0.9709065914154053, -34.33410705626011 -0.681712731719017 M0.7803856804966927 -0.0028167441487312317 C-7.24243448458612 0.08671231970191007, -14.01775377176702 0.2988919261097909, -35.491398863494396 1.6854602620005608" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(1017.5202442733594 258.5144794614512) rotate(0 54 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">next restock</text></g><g transform="translate(1197.5202442733594 263.5144794614512) rotate(0 40 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">unknown</text></g><g transform="translate(1150.5202442733594 252.01447946145117) rotate(0 94.5 23)"><path d="M0 0 C70.95094501152634 0, 141.9018900230527 0, 189 0 M0 0 C63.35328986272216 0, 126.70657972544431 0, 189 0 M189 0 C189 13.924661253392697, 189 27.849322506785395, 189 46 M189 0 C189 12.685054327547553, 189 25.370108655095105, 189 46 M189 46 C127.70845397338272 46, 66.41690794676542 46, 0 46 M189 46 C122.6631328381598 46, 56.32626567631959 46, 0 46 M0 46 C0 27.616077138483522, 0 9.232154276967044, 0 0 M0 46 C0 29.85423505157232, 0 13.708470103144641, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1493.9141836672989 256.7974508453981) rotate(0 42.85000000000002 19.5)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.832670802688257 3.9887657545743176, 3.9267984294379623 1.5797474920727463, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C0.9784212350667891 4.971467469048262, 2.2182992941950266 3.545150921020635, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C3.37460858018232 8.311981596267827, 6.6160717794970285 4.5831047386066475, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C3.1916574118686847 8.522442840360005, 6.250169442869758 5.004027226791005, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C3.473213240430706 14.295562257136579, 7.074737924055251 10.152482043268261, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C4.64777413008577 12.94438451731999, 9.423859703365379 7.450126563635084, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C5.737950658843504 17.787292227166486, 11.209610555951786 11.492867546474958, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C5.81762107869453 17.695641893179832, 11.368951395653838 11.30956687850165, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C8.842980156026423 20.312376736941175, 17.681126374379073 10.145252548948452, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C10.475407666861928 18.43448370139758, 20.945981396050083 6.389466477861255, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C9.226002889761762 25.968771831627873, 18.708628665911203 15.060258721245951, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C9.014899617064208 26.211618367200103, 18.286422120516093 15.545951792390408, 31.89026953414718 -0.10348448890603734 M2.1061564055129054 40.256230638194594 C14.395472293624229 26.118989894152126, 26.684788181735552 11.981749150109657, 36.877284942009794 0.25662288638767805 M2.1061564055129054 40.256230638194594 C15.87821753425575 24.413286613372307, 29.650278662998595 8.570342588550023, 36.877284942009794 0.25662288638767805 M7.093171813375516 40.6163380134883 C20.763277283758065 24.89068055698112, 34.43338275414061 9.165023100473938, 42.520359378862906 -0.13797931854138312 M7.093171813375516 40.6163380134883 C20.995815386415636 24.62317607020873, 34.89845895945576 8.630014126929158, 42.520359378862906 -0.13797931854138312 M12.736246250228632 40.221735808559245 C26.521045039779274 24.364138781161774, 40.305843829329916 8.506541753764303, 47.50737478672552 0.22212805675232872 M12.736246250228632 40.221735808559245 C22.469745334088707 29.02462597077197, 32.20324441794878 17.827516132984698, 47.50737478672552 0.22212805675232872 M17.723261658091243 40.58184318385296 C31.71044703869748 24.49142701605997, 45.69763241930372 8.401010848266978, 53.15044922357863 -0.1724741481767289 M17.723261658091243 40.58184318385296 C28.99194369025733 27.618707383030046, 40.26062572242342 14.65557158220713, 53.15044922357863 -0.1724741481767289 M22.710277065953854 40.941950559146676 C32.31425868693094 29.893833518843415, 41.918240307908036 18.84571647854015, 58.13746463144125 0.1876332271169865 M22.710277065953854 40.941950559146676 C35.053310785473414 26.742914518947746, 47.396344504992975 12.543878478748816, 58.13746463144125 0.1876332271169865 M28.353351502806966 40.54734835421761 C37.94887564361349 29.508960531907263, 47.54439978442001 18.47057270959692, 63.78053906829436 -0.20696897781207468 M28.353351502806966 40.54734835421761 C39.671166823849696 27.52769117012815, 50.988982144892425 14.508033986038686, 63.78053906829436 -0.20696897781207468 M33.34036691066958 40.90745572951133 C42.910973032649395 29.897732808829765, 52.4815791546292 18.888009888148204, 68.76755447615697 0.1531383974816336 M33.34036691066958 40.90745572951133 C40.845781098123865 32.273464365155576, 48.35119528557814 23.639473000799825, 68.76755447615697 0.1531383974816336 M38.98344134752269 40.51285352458227 C47.85792328245242 30.303929876185542, 56.73240521738214 20.09500622778881, 74.41062891301009 -0.2414638074474169 M38.98344134752269 40.51285352458227 C51.850272077486025 25.711257951772012, 64.71710280744935 10.909662378961755, 74.41062891301009 -0.2414638074474169 M43.97045675538531 40.872960899875984 C57.216362961433376 25.635288875425577, 70.46226916748145 10.397616850975169, 79.3976443208727 0.11864356784629138 M43.97045675538531 40.872960899875984 C57.89790854275577 24.85126037059122, 71.82536033012623 8.829559841306455, 79.3976443208727 0.11864356784629138 M49.613531192238426 40.47835869494692 C58.74595402494579 29.972707986816566, 67.87837685765317 19.46705727868621, 85.04071875772581 -0.27595863708276624 M49.613531192238426 40.47835869494692 C61.246167829479475 27.096541014783178, 72.87880446672051 13.714723334619432, 85.04071875772581 -0.27595863708276624 M54.60054660010103 40.838466070240635 C62.96835188884398 31.212407228293863, 71.33615717758694 21.586348386347094, 88.0595570786169 2.348277478879261 M54.60054660010103 40.838466070240635 C65.56105143686412 28.229847578835304, 76.52155627362723 15.62122908742997, 88.0595570786169 2.348277478879261 M60.24362103695415 40.44386386531157 C68.82577589031709 30.571224056124393, 77.40793074368003 20.698584246937216, 88.45415928354596 7.991351915732373 M60.24362103695415 40.44386386531157 C66.07067846212402 33.74060109633355, 71.89773588729389 27.037338327355528, 88.45415928354596 7.991351915732373 M65.23063644481675 40.80397124060529 C71.06352488858407 34.09400065205085, 76.89641333235139 27.384030063496404, 88.19270245948451 14.389135932808273 M65.23063644481675 40.80397124060529 C73.56723629186938 31.213810152912455, 81.903836138922 21.623649065219617, 88.19270245948451 14.389135932808273 M70.87371088166988 40.40936903567623 C75.80055067590764 34.74168818894585, 80.7273904701454 29.074007342215474, 87.93124563542307 20.786919949884158 M70.87371088166988 40.40936903567623 C76.02338835294613 34.485342765342246, 81.17306582422239 28.56131649500827, 87.93124563542307 20.786919949884158 M75.8607262895325 40.76947641096994 C78.70849720079879 37.49349072364621, 81.55626811206508 34.217505036322486, 88.32584784035213 26.429994386737274 M75.8607262895325 40.76947641096994 C80.34716357299014 35.60842069910181, 84.83360085644779 30.44736498723369, 88.32584784035213 26.429994386737274 M81.5038007263856 40.374874206040886 C84.11595924225449 37.369929574732005, 86.72811775812337 34.36498494342312, 88.06439101629068 32.82777840381317 M81.5038007263856 40.374874206040886 C83.01921927251676 38.6315845868548, 84.53463781864794 36.88829496766872, 88.06439101629068 32.82777840381317" stroke="#fa5252" stroke-width="0.5" fill="none"></path><path d="M0 0 C27.48174813024704 0, 54.96349626049408 0, 85.70000000000013 0 M0 0 C23.505595291927495 0, 47.01119058385499 0, 85.70000000000013 0 M85.70000000000013 0 C85.70000000000013 11.344363928586246, 85.70000000000013 22.68872785717249, 85.70000000000013 39 M85.70000000000013 0 C85.70000000000013 10.094785391539336, 85.70000000000013 20.189570783078672, 85.70000000000013 39 M85.70000000000013 39 C51.926018922403536 39, 18.15203784480694 39, 0 39 M85.70000000000013 39 C56.20642761819073 39, 26.71285523638133 39, 0 39 M0 39 C0 27.112638091295956, 0 15.225276182591912, 0 0 M0 39 C0 29.743110812455413, 0 20.48622162491083, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1508.0141836672988 264.59745084539827) rotate(0 25 11.5)"><text x="25" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">never</text></g><g transform="translate(1031.2702442733594 1351.859549495717) rotate(0 54 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">next restock</text></g><g transform="translate(1211.2702442733594 1356.859549495717) rotate(0 25 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">never</text></g><g transform="translate(1164.2702442733594 1345.359549495717) rotate(0 94.5 23)"><path d="M0 0 C43.93486205711961 0, 87.86972411423922 0, 189 0 M0 0 C68.47068202123046 0, 136.94136404246092 0, 189 0 M189 0 C189 11.259486769139768, 189 22.518973538279536, 189 46 M189 0 C189 17.517849661409855, 189 35.03569932281971, 189 46 M189 46 C146.6980354629457 46, 104.3960709258914 46, 0 46 M189 46 C115.34704683199524 46, 41.694093663990486 46, 0 46 M0 46 C0 35.74880533367396, 0 25.497610667347907, 0 0 M0 46 C0 28.277714131772516, 0 10.555428263545032, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1429.4141836672989 1356.1425208796638) rotate(0 21.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">clear</text></g><g transform="translate(1507.6641836672989 1350.1425208796638) rotate(0 42.85000000000002 19.5)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.1680636657135124 4.75330880816367, 2.597584155488473 3.1088335992514513, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.3595743526068416 4.53300096431639, 2.9806055292751314 2.6682179115568903, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C2.4478070758704646 9.378144766593092, 4.762468770873318 6.7154310792571765, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C2.3163147367899652 9.52940939926289, 4.499484092712319 7.017960344596775, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C6.023305356175783 11.36201685168006, 12.174922155545405 4.285391232355222, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C5.75875087257915 11.666351971598296, 11.64581318835214 4.894061472191693, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C6.375578048976325 17.053785821978902, 12.484865336217428 10.025854736099792, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C6.41004029965436 17.01414153755716, 12.553789837573499 9.946566167256305, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C6.827577750615223 22.630831991963447, 13.650321563556673 14.782163058992994, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C7.413960704011991 21.95627556784286, 14.82308747035021 13.433050210751812, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C10.72703285783447 24.24203437806507, 21.710688602056617 11.606783814120345, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C6.754050063429236 28.812428267181495, 13.76472301324615 20.747571592353193, 31.89026953414718 -0.10348448890603734 M2.1061564055129054 40.256230638194594 C14.642324438868245 25.835018985008674, 27.178492472223585 11.413807331822756, 36.877284942009794 0.25662288638767805 M2.1061564055129054 40.256230638194594 C11.04377932938536 29.974671590917456, 19.981402253257816 19.693112543640318, 36.877284942009794 0.25662288638767805 M7.093171813375516 40.6163380134883 C21.14128179646881 24.455836107771706, 35.1893917795621 8.295334202055109, 42.520359378862906 -0.13797931854138312 M7.093171813375516 40.6163380134883 C19.96728173679834 25.806368686492192, 32.84139166022117 10.996399359496078, 42.520359378862906 -0.13797931854138312 M12.736246250228632 40.221735808559245 C21.78015876421793 29.81790457479522, 30.824071278207228 19.414073341031195, 47.50737478672552 0.22212805675232872 M12.736246250228632 40.221735808559245 C20.85053294298741 30.887316750075698, 28.96481963574619 21.552897691592147, 47.50737478672552 0.22212805675232872 M17.723261658091243 40.58184318385296 C30.729227301916936 25.62019120179402, 43.73519294574263 10.658539219735083, 53.15044922357863 -0.1724741481767289 M17.723261658091243 40.58184318385296 C25.523898748441372 31.60823671891775, 33.324535838791505 22.63463025398254, 53.15044922357863 -0.1724741481767289 M22.710277065953854 40.941950559146676 C30.290159765407076 32.22229297125459, 37.8700424648603 23.5026353833625, 58.13746463144125 0.1876332271169865 M22.710277065953854 40.941950559146676 C31.891231849548355 30.38047022797496, 41.072186633142856 19.81898989680325, 58.13746463144125 0.1876332271169865 M28.353351502806966 40.54734835421761 C37.29675856475941 30.259135417230254, 46.24016562671184 19.970922480242898, 63.78053906829436 -0.20696897781207468 M28.353351502806966 40.54734835421761 C42.26060010749494 24.548888928016098, 56.167848712182916 8.550429501814584, 63.78053906829436 -0.20696897781207468 M33.34036691066958 40.90745572951133 C46.267118746162495 26.036928809974075, 59.19387058165542 11.166401890436823, 68.76755447615697 0.1531383974816336 M33.34036691066958 40.90745572951133 C43.78269662308831 28.894929530559565, 54.225026335507046 16.882403331607804, 68.76755447615697 0.1531383974816336 M38.98344134752269 40.51285352458227 C50.99459514721693 26.69560165914144, 63.00574894691116 12.878349793700604, 74.41062891301009 -0.2414638074474169 M38.98344134752269 40.51285352458227 C53.051938699783015 24.32889863346957, 67.12043605204335 8.144943742356872, 74.41062891301009 -0.2414638074474169 M43.97045675538531 40.872960899875984 C56.12724425861781 26.888176622858133, 68.28403176185031 12.903392345840285, 79.3976443208727 0.11864356784629138 M43.97045675538531 40.872960899875984 C51.517456439565606 32.19113089388803, 59.064456123745906 23.509300887900075, 79.3976443208727 0.11864356784629138 M49.613531192238426 40.47835869494692 C56.73158547110044 32.28997393165974, 63.84963974996244 24.101589168372556, 85.04071875772581 -0.27595863708276624 M49.613531192238426 40.47835869494692 C58.92890103844186 29.762251522295255, 68.24427088464529 19.04614434964359, 85.04071875772581 -0.27595863708276624 M54.60054660010103 40.838466070240635 C63.51834177647235 30.579716237275164, 72.43613695284365 20.320966404309697, 88.0595570786169 2.348277478879261 M54.60054660010103 40.838466070240635 C67.96149522775357 25.468452878486247, 81.32244385540612 10.098439686731854, 88.0595570786169 2.348277478879261 M60.24362103695415 40.44386386531157 C68.69597646440566 30.72054121496833, 77.14833189185715 20.997218564625086, 88.45415928354596 7.991351915732373 M60.24362103695415 40.44386386531157 C69.59998204984933 29.68060174952259, 78.95634306274451 18.91733963373361, 88.45415928354596 7.991351915732373 M65.23063644481675 40.80397124060529 C73.04455754813084 31.815083266835224, 80.85847865144494 22.826195293065158, 88.19270245948451 14.389135932808273 M65.23063644481675 40.80397124060529 C73.3015613409806 31.519434223004897, 81.37248623714444 22.2348972054045, 88.19270245948451 14.389135932808273 M70.87371088166988 40.40936903567623 C77.42636322445753 32.87140479703058, 83.97901556724518 25.33344055838493, 87.93124563542307 20.786919949884158 M70.87371088166988 40.40936903567623 C75.26372668564532 35.359233547581944, 79.65374248962075 30.30909805948766, 87.93124563542307 20.786919949884158 M75.8607262895325 40.76947641096994 C79.06707914381792 37.080989384997075, 82.27343199810335 33.392502359024206, 88.32584784035213 26.429994386737274 M75.8607262895325 40.76947641096994 C79.34946265055413 36.75614432012746, 82.83819901157577 32.74281222928498, 88.32584784035213 26.429994386737274 M81.5038007263856 40.374874206040886 C83.41321672213974 38.17834236828289, 85.32263271789387 35.98181053052489, 88.06439101629068 32.82777840381317 M81.5038007263856 40.374874206040886 C82.85958293045782 38.815225191403755, 84.21536513453002 37.25557617676662, 88.06439101629068 32.82777840381317" stroke="#fa5252" stroke-width="0.5" fill="none"></path><path d="M0 0 C31.05126833669846 0, 62.10253667339692 0, 85.70000000000013 0 M0 0 C25.29206354983155 0, 50.5841270996631 0, 85.70000000000013 0 M85.70000000000013 0 C85.70000000000013 7.99688525274396, 85.70000000000013 15.99377050548792, 85.70000000000013 39 M85.70000000000013 0 C85.70000000000013 14.824664580076934, 85.70000000000013 29.64932916015387, 85.70000000000013 39 M85.70000000000013 39 C54.724368588999 39, 23.74873717799786 39, 0 39 M85.70000000000013 39 C67.95390589348982 39, 50.20781178697951 39, 0 39 M0 39 C0 26.822433661669493, 0 14.644867323338985, 0 0 M0 39 C0 24.301500666886568, 0 9.603001333773136, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1521.7641836672988 1357.942520879664) rotate(0 25 11.5)"><text x="25" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">never</text></g><g transform="translate(916.5709458336519 1853.4558419016075) rotate(0 412 251.56944444444457)"><path d="M0 0 C237.1811243116856 0, 474.3622486233712 0, 824 0 M0 0 C172.54678277373316 0, 345.0935655474663 0, 824 0 M824 0 C824 112.20485208479487, 824 224.40970416958973, 824 503.13888888888914 M824 0 C824 119.43370529266288, 824 238.86741058532576, 824 503.13888888888914 M824 503.13888888888914 C570.5043474137783 503.13888888888914, 317.0086948275566 503.13888888888914, 0 503.13888888888914 M824 503.13888888888914 C513.3626734793186 503.13888888888914, 202.72534695863715 503.13888888888914, 0 503.13888888888914 M0 503.13888888888914 C0 365.26225807884106, 0 227.38562726879297, 0 0 M0 503.13888888888914 C0 376.0602100148592, 0 248.98153114082922, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1009.5709458336516 1923.4558419016075) rotate(0 25 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Stock</text></g><g transform="translate(1046.9876125003182 2113.8566355524) rotate(0 81 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">current stock is 15</text></g><g transform="translate(995.3934566561632 2229.455278815496) rotate(0 288.4999999999999 28.5)"><path d="M0 0 C115.43863970711827 0, 230.87727941423654 0, 576.9999999999999 0 M0 0 C117.08345114514229 0, 234.16690229028458 0, 576.9999999999999 0 M576.9999999999999 0 C576.9999999999999 15.664222944527864, 576.9999999999999 31.32844588905573, 576.9999999999999 57 M576.9999999999999 0 C576.9999999999999 11.606445883959532, 576.9999999999999 23.212891767919064, 576.9999999999999 57 M576.9999999999999 57 C453.28450038954605 57, 329.5690007790922 57, 0 57 M576.9999999999999 57 C367.806977636367 57, 158.61395527273407 57, 0 57 M0 57 C0 45.09641448184848, 0 33.192828963696954, 0 0 M0 57 C0 39.794306612759826, 0 22.58861322551965, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1490.393456656163 2229.455278815496) rotate(0 41 29)"><path d="M0 0 C19.06852476447821 0, 38.13704952895642 0, 82 0 M0 0 C19.28069086223841 0, 38.56138172447682 0, 82 0 M82 0 C82 23.10410188883543, 82 46.20820377767086, 82 58 M82 0 C82 13.37995346337557, 82 26.75990692675114, 82 58 M82 58 C60.44384906440973 58, 38.887698128819466 58, 0 58 M82 58 C49.94147968143225 58, 17.882959362864497 58, 0 58 M0 58 C0 42.55719810277223, 0 27.11439620554447, 0 0 M0 58 C0 45.967039696872234, 0 33.93407939374447, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(1529.393456656163 2241.455278815496) rotate(0 0 17)"><path d="M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34 M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1529.393456656163 2241.455278815496) rotate(0 0 17)"><path d="M-5.814342436536368 18.025225446639556 C-4.172222794085663 22.536912084315766, -2.5301031516349584 27.04859872199198, 0 34 M-5.814342436536368 18.025225446639556 C-3.6142086520908348 24.070043339182902, -1.4140748676453017 30.11486123172625, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1529.393456656163 2241.455278815496) rotate(0 0 17)"><path d="M5.814342436536368 18.025225446639556 C4.172222794085663 22.536912084315766, 2.5301031516349584 27.04859872199198, 0 34 M5.814342436536368 18.025225446639556 C3.6142086520908348 24.070043339182902, 1.4140748676453017 30.11486123172625, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(1026.3793720786027 2245.455278815496) rotate(0 35.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">address</text></g><g transform="translate(922.2888234866489 1782.589056174199) rotate(0 244 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"># updating product: initial state</text></g><g transform="translate(1046.4061697165266 2180.939090707132) rotate(0 54 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">next restock</text></g><g transform="translate(1401.120455430812 2172.1533764214173) rotate(0 36 23)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.0909203447289906 4.842052047452373, 2.4432975135194295 3.2863200778288584, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C0.9609887858427564 4.991521207896073, 2.183434395746961 3.585258398716258, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C4.055934280738017 7.528206035320831, 7.978723180608424 3.015553616712655, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C2.954120567050224 8.795697722190123, 5.775095753232837 5.5505369904512385, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C3.931789477079368 13.76803064219365, 7.9918903973525754 9.097418813382406, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C3.3020586491481456 14.49245309169886, 6.73242874149013 10.546263712392824, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C8.176788733731076 14.981729955488115, 16.08728670572693 5.881743003118217, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C4.890129338938814 18.76259908855326, 9.513967916142406 13.443481269248503, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C5.323469502644222 24.361110601469832, 10.64210506761467 18.242720278005763, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C7.166012140537533 22.241507761879706, 14.327190343401293 14.003514598825511, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C9.004653777300126 26.22340485757015, 18.26593044098793 15.569524773130503, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C11.149446486180546 23.756103085236145, 22.55551585874877 10.634921228462495, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C12.671130608757073 28.10261809167754, 25.204281898972763 13.68487680449218, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C13.073179670552559 27.640113552835167, 26.008380022563735 12.759867726807432, 36.877284942009794 0.25662288638767805 M1.1886405524609494 47.40872423549325 C13.602967845916378 33.127674320200626, 26.017295139371807 18.846624404907992, 42.520359378862906 -0.13797931854138312 M1.1886405524609494 47.40872423549325 C17.00985498266705 29.208498991115004, 32.83106941287315 11.008273746736755, 42.520359378862906 -0.13797931854138312 M6.831714989314069 47.014122030564195 C15.36440546127615 37.19838448302329, 23.89709593323823 27.382646935482388, 47.50737478672552 0.22212805675232872 M6.831714989314069 47.014122030564195 C19.931300316280954 31.94477292272559, 33.030885643247835 16.87542381488699, 47.50737478672552 0.22212805675232872 M11.818730397176676 47.3742294058579 C23.96493341124092 33.40162119078579, 36.11113642530516 19.429012975713682, 53.15044922357863 -0.1724741481767289 M11.818730397176676 47.3742294058579 C25.335211234181067 31.82529687415986, 38.85169207118546 16.276364342461818, 53.15044922357863 -0.1724741481767289 M17.461804834029795 46.979627200928846 C26.923227680139938 36.095505271404654, 36.38465052625008 25.211383341880463, 58.13746463144125 0.1876332271169865 M17.461804834029795 46.979627200928846 C32.18211722848127 30.045844877928026, 46.902429622932736 13.112062554927206, 58.13746463144125 0.1876332271169865 M22.448820241892403 47.33973457622256 C32.21982389418312 36.09948066778622, 41.99082754647384 24.859226759349877, 63.78053906829436 -0.20696897781207468 M22.448820241892403 47.33973457622256 C35.79387852241059 31.98800113779131, 49.13893680292877 16.63626769936006, 63.78053906829436 -0.20696897781207468 M28.091894678745525 46.9451323712935 C41.15523817334838 31.917474722426277, 54.21858166795123 16.889817073559055, 68.76755447615697 0.1531383974816336 M28.091894678745525 46.9451323712935 C42.866012590319265 29.94945388126103, 57.640130501893 12.953775391228561, 68.76755447615697 0.1531383974816336 M33.07891008660813 47.30523974658722 C48.41568418493783 29.66229935518325, 63.75245828326753 12.019358963779283, 73.09851085502908 1.2679553529981291 M33.07891008660813 47.30523974658722 C41.81100230326506 37.26011673160461, 50.54309451992199 27.214993716622008, 73.09851085502908 1.2679553529981291 M38.72198452346125 46.91063754165816 C48.26506034763322 35.93258460581613, 57.80813617180518 24.954531669974106, 73.49311305995813 6.911029789851241 M38.72198452346125 46.91063754165816 C50.20061821505383 33.70597998478739, 61.67925190664641 20.501322427916612, 73.49311305995813 6.911029789851241 M43.70899993132386 47.27074491695187 C51.89049263716788 37.859014184239776, 60.0719853430119 28.447283451527678, 73.23165623589668 13.30881380692713 M43.70899993132386 47.27074491695187 C54.73073308969366 34.591691298743015, 65.75246624806346 21.912637680534164, 73.23165623589668 13.30881380692713 M49.35207436817697 46.87614271202281 C58.30371628344327 36.57845665994509, 67.25535819870957 26.280770607867368, 72.97019941183524 19.706597824003016 M49.35207436817697 46.87614271202281 C58.308125954591326 36.57338391357013, 67.26417754100568 26.270625115117458, 72.97019941183524 19.706597824003016 M54.339089776039586 47.23625008731652 C60.96690458165455 39.61182132602541, 67.59471938726952 31.98739256473429, 73.3648016167643 25.34967226085613 M54.339089776039586 47.23625008731652 C59.307395360843515 41.52086830513838, 64.27570094564744 35.80548652296024, 73.3648016167643 25.34967226085613 M59.9821642128927 46.84164788238747 C62.722751713026106 43.68896260500919, 65.46333921315951 40.53627732763091, 73.10334479270284 31.747456277932027 M59.9821642128927 46.84164788238747 C64.43769243441663 41.71614897886472, 68.89322065594057 36.59065007534198, 73.10334479270284 31.747456277932027 M64.96917962075531 47.20175525768118 C67.65326893737495 44.11406370568252, 70.3373582539946 41.02637215368385, 73.49794699763191 37.39053071478514 M64.96917962075531 47.20175525768118 C67.24603681104708 44.58253067821555, 69.52289400133883 41.96330609874992, 73.49794699763191 37.39053071478514 M69.95619502861793 47.561862632974886 C70.69600811909511 46.7108050264414, 71.4358212095723 45.859747419907904, 73.23649017357046 43.78831473186103 M69.95619502861793 47.561862632974886 C71.1135379226463 46.23049193136291, 72.27088081667466 44.899121229750946, 73.23649017357046 43.78831473186103" stroke="#4c6ef5" stroke-width="0.5" fill="none"></path><path d="M0 0 C28.68456582427025 0, 57.3691316485405 0, 72 0 M0 0 C21.353178030252458 0, 42.706356060504916 0, 72 0 M72 0 C72 15.29855439811945, 72 30.5971087962389, 72 46 M72 0 C72 10.088826654851436, 72 20.177653309702873, 72 46 M72 46 C46.18587675690651 46, 20.37175351381302 46, 0 46 M72 46 C55.007525628805155 46, 38.01505125761032 46, 0 46 M0 46 C0 34.933114741742614, 0 23.86622948348522, 0 0 M0 46 C0 33.28402233272791, 0 20.568044665455815, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1043.0038774082552 1977.5509344581742) rotate(0 40 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">incoming</text></g><g transform="translate(1229.4931932183251 1978.6798043610443) rotate(0 5.5 11.5)"><text x="5.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">0</text></g><g transform="translate(1043.0038774082552 2028.5509344581742) rotate(0 42 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">notify lost</text></g><g transform="translate(1229.4931932183251 2035.6798043610443) rotate(0 5.5 11.5)"><text x="5.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">0</text></g><g transform="translate(1195.4985353132902 1967.6153694096092) rotate(0 52.5 20.5)"><path d="M0 0 C24.69663779810071 0, 49.39327559620142 0, 105 0 M0 0 C32.88236404582858 0, 65.76472809165716 0, 105 0 M105 0 C105 12.499904776364566, 105 24.999809552729133, 105 41 M105 0 C105 11.410576330870391, 105 22.821152661740783, 105 41 M105 41 C67.12486464902759 41, 29.249729298055158 41, 0 41 M105 41 C76.42338036373258 41, 47.846760727465146 41, 0 41 M0 41 C0 28.070744704455137, 0 15.141489408910275, 0 0 M0 41 C0 29.45000053718686, 0 17.90000107437372, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1196.4985353132902 2024.6153694096092) rotate(0 51 22.5)"><path d="M0 0 C23.705919201672078 0, 47.411838403344156 0, 102 0 M0 0 C20.977860300242902 0, 41.955720600485805 0, 102 0 M102 0 C102 11.528187688440084, 102 23.05637537688017, 102 45 M102 0 C102 15.508610609918835, 102 31.01722121983767, 102 45 M102 45 C71.24600254744291 45, 40.492005094885826 45, 0 45 M102 45 C66.05086522847414 45, 30.101730456948275 45, 0 45 M0 45 C0 29.324226681143045, 0 13.64845336228609, 0 0 M0 45 C0 31.80285060033202, 0 18.60570120066404, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1418.120455430812 2182.6533764214173) rotate(0 21.5 11.5)"><text x="21.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">clear</text></g><g transform="translate(1501.303345058886 2172.07664661918) rotate(0 36 23)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C0.965600441736221 4.986216104651257, 2.19265770753389 3.574648192226626, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.6133162138232222 4.241104343583608, 3.4880892517078927 2.084424670091326, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C3.648335235138404 7.997095100192062, 7.163525089409197 3.9533317464551168, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C3.3500231501029547 8.34026389830907, 6.566900919338298 4.639669342689134, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C5.57169766949688 11.881532066893634, 11.271706782187598 5.324421662782372, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C4.36987753206746 13.264067984154451, 8.86806650732876 8.089493497304003, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C6.856252205894873 16.50083345769221, 13.446213650054524 8.919950007526408, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C5.311331628755643 18.27806128129883, 10.356372495776064 12.474405654739646, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C8.394970302828646 20.82775311818362, 16.78510666798352 11.176005311433336, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C6.507872769949093 22.998610501352967, 13.010911602224413 15.517720077772035, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C9.84100486007546 25.261292994600325, 19.938632606538597 13.645301047190852, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C7.544475196613628 27.903148165692713, 15.345573279614934 18.929011389375628, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C11.607492680632955 29.326193560913538, 23.077006042724527 16.132027742964173, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C12.681829312882755 28.090310640453154, 25.225679307224127 13.660261902043398, 36.877284942009794 0.25662288638767805 M1.1886405524609494 47.40872423549325 C12.948784612455563 33.88022604450763, 24.708928672450178 20.351727853522007, 42.520359378862906 -0.13797931854138312 M1.1886405524609494 47.40872423549325 C16.383884466024085 29.928595697312886, 31.579128379587225 12.44846715913252, 42.520359378862906 -0.13797931854138312 M6.831714989314069 47.014122030564195 C16.27626263619843 36.1494127970949, 25.720810283082795 25.284703563625595, 47.50737478672552 0.22212805675232872 M6.831714989314069 47.014122030564195 C22.162332380717757 29.378264120300425, 37.49294977212145 11.742406210036656, 47.50737478672552 0.22212805675232872 M11.818730397176676 47.3742294058579 C22.63473288331568 34.931841853379694, 33.45073536945469 22.489454300901485, 53.15044922357863 -0.1724741481767289 M11.818730397176676 47.3742294058579 C27.60017800282167 29.219750660110254, 43.38162560846666 11.065271914362604, 53.15044922357863 -0.1724741481767289 M17.461804834029795 46.979627200928846 C28.03773077370014 34.813416122822915, 38.61365671337049 22.647205044716983, 58.13746463144125 0.1876332271169865 M17.461804834029795 46.979627200928846 C28.73180183369619 34.01497870303706, 40.001798833362585 21.050330205145276, 58.13746463144125 0.1876332271169865 M22.448820241892403 47.33973457622256 C37.72516161241202 29.76631408565349, 53.00150298293164 12.19289359508442, 63.78053906829436 -0.20696897781207468 M22.448820241892403 47.33973457622256 C37.506818107690144 30.01748955540745, 52.56481597348788 12.69524453459234, 63.78053906829436 -0.20696897781207468 M28.091894678745525 46.9451323712935 C38.80601667841654 34.61994491176037, 49.52013867808756 22.29475745222724, 68.76755447615697 0.1531383974816336 M28.091894678745525 46.9451323712935 C39.37094751487938 33.97006632522858, 50.65000035101323 20.995000279163666, 68.76755447615697 0.1531383974816336 M33.07891008660813 47.30523974658722 C41.875261774474744 37.18619466606027, 50.671613462341355 27.067149585533315, 73.09851085502908 1.2679553529981291 M33.07891008660813 47.30523974658722 C45.35421394435585 33.18411799959606, 57.629517802103564 19.062996252604908, 73.09851085502908 1.2679553529981291 M38.72198452346125 46.91063754165816 C52.548988125867446 31.004489430918987, 66.37599172827363 15.09834132017981, 73.49311305995813 6.911029789851241 M38.72198452346125 46.91063754165816 C50.037153528279696 33.89402459614863, 61.35232253309814 20.8774116506391, 73.49311305995813 6.911029789851241 M43.70899993132386 47.27074491695187 C52.899531906204274 36.69824728749493, 62.09006388108468 26.125749658037993, 73.23165623589668 13.30881380692713 M43.70899993132386 47.27074491695187 C52.95433495201077 36.63520359497965, 62.19966997269768 25.99966227300743, 73.23165623589668 13.30881380692713 M49.35207436817697 46.87614271202281 C56.56838460507855 38.57472739878568, 63.78469484198013 30.273312085548547, 72.97019941183524 19.706597824003016 M49.35207436817697 46.87614271202281 C56.00765249429886 39.219775903940985, 62.66323062042075 31.563409095859154, 72.97019941183524 19.706597824003016 M54.339089776039586 47.23625008731652 C58.72711598403206 42.188403367584165, 63.11514219202454 37.14055664785182, 73.3648016167643 25.34967226085613 M54.339089776039586 47.23625008731652 C58.148177076502364 42.85439639651738, 61.95726437696514 38.47254270571823, 73.3648016167643 25.34967226085613 M59.9821642128927 46.84164788238747 C64.14588211683927 42.05183834910684, 68.30960002078587 37.262028815826206, 73.10334479270284 31.747456277932027 M59.9821642128927 46.84164788238747 C64.17158984037532 42.022264996129415, 68.36101546785792 37.202882109871354, 73.10334479270284 31.747456277932027 M64.96917962075531 47.20175525768118 C67.11690508387139 44.73107973752833, 69.26463054698746 42.26040421737549, 73.49794699763191 37.39053071478514 M64.96917962075531 47.20175525768118 C67.50200064914837 44.28807796547278, 70.03482167754143 41.374400673264375, 73.49794699763191 37.39053071478514 M69.95619502861793 47.561862632974886 C70.7788649183992 46.61548918219853, 71.60153480818046 45.669115731422174, 73.23649017357046 43.78831473186103 M69.95619502861793 47.561862632974886 C71.01649475781093 46.342127322326256, 72.07679448700394 45.12239201167763, 73.23649017357046 43.78831473186103" stroke="#4c6ef5" stroke-width="0.5" fill="none"></path><path d="M0 0 C24.9990046441555 0, 49.998009288311 0, 72 0 M0 0 C18.89581623673439 0, 37.79163247346878 0, 72 0 M72 0 C72 12.982670523226261, 72 25.965341046452522, 72 46 M72 0 C72 17.12471861690283, 72 34.24943723380566, 72 46 M72 46 C51.709999948740005 46, 31.41999989748001 46, 0 46 M72 46 C43.89292697310448 46, 15.785853946208952 46, 0 46 M0 46 C0 36.00459248870611, 0 26.00918497741222, 0 0 M0 46 C0 33.257136107981204, 0 20.514272215962407, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1509.803345058886 2182.57664661918) rotate(0 25 11.5)"><text x="25" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">never</text></g><g transform="translate(1182.2293654670493 2176.6061805114414) rotate(0 71.39795918367349 18.459183673469397)"><path d="M1.672937735915184 -1.6225496381521225 L144.7023351262419 0.6433686167001724 L142.84241510137008 37.36221537571777 L0.9881971925497055 38.18504891377319" stroke="none" stroke-width="0" fill="#fff"></path><path d="M-0.5037814229726791 1.9669316858053207 C33.604280259034475 0.22042079466490105, 61.80305544201819 -0.6517978141913001, 142.04475621088432 0.6515453904867172 M-0.9637814238667488 -0.6931114718317986 C34.712639796779484 -0.3664882219217871, 67.35481266537494 0.17317866917623537, 142.61823804630922 -0.8067768141627312 M141.08415058954643 -0.7424022108316422 C142.32678374701774 10.92371443514616, 143.7166186278466 23.0008265645224, 144.241448200783 38.08895713668693 M143.4214473511188 0.9095756486058235 C143.07612582708353 14.524902024606648, 142.96508976484293 28.620887885470754, 142.61397393002198 36.27843323182691 M140.9726150403826 36.24347144943107 C101.76526391678019 37.67087043235949, 65.58319660665431 39.26389230201892, 1.8075202852487564 35.73005658965934 M142.8144610668628 35.993015675064214 C107.07914770222747 36.24827819009365, 71.14698832929136 35.37344007630886, -0.8270853236317635 36.682710318084844 M0.10155333578586578 34.99943906646598 C-0.3544819420226377 23.263524874451793, 0.09794449154059473 9.050910853336042, -0.45962439477443695 1.4708398431539536 M0.24138277024030685 36.7060696167909 C0.18824374114524345 28.4890349346916, 0.08326541816245536 18.01681989370558, 0.1552075669169426 0.02446264773607254" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1216.8773246507226 2183.0653641849112) rotate(0 5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(1247.3773246507226 2182.5653641849112) rotate(0 5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(1336.3773246507226 2175.5653641849112) rotate(0 17.75 17.75)"><path d="M0.6433686167001724 0.04649673402309418 L35.94384802877903 0.9881971925497055 L36.76668156683445 35.485912665724754 L-0.00971280038356781 34.65341268479824" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0.26330743730068207 -1.8866940587759018 C9.146876802667975 -1.0634566342458127, 20.163121338933706 -1.5647502934560178, 34.20532165467739 0.581592932343483 M0.04875726252794266 -0.43818051367998123 C7.817000098899007 -0.46741115961223845, 13.650375076383353 -0.21332728777080778, 35.575800843536854 0.9825183674693108 M35.06613479554653 0.8927158266305923 C35.65389089290053 9.057142027840019, 36.538813397325576 16.762965323776008, 36.33467184007168 33.94439209997654 M36.10715574771166 0.015097789466381073 C36.60829468693584 12.688683455064893, 35.18296524014324 25.481585221737625, 34.94225139170885 36.41692917793989 M34.94316564500332 36.54884995520115 C29.122550920024516 36.970293610058725, 19.484416053444146 34.214208691082895, -0.16343463957309723 34.34651316702366 M35.653476901352406 35.98350518196821 C24.062812204286455 34.79696834180504, 13.832689804583786 36.223613859154284, -0.6298890635371208 36.12501399964094 M-0.3658539205789566 35.36539973318577 C-0.9488696200028062 24.21011843420565, 1.8114496129378677 12.749554542452096, -0.06487669050693512 0.3372725397348404 M0.6342539265751839 35.57128971070051 C-0.6990090813860297 24.148298732563852, 0.09982834193855522 13.322651199251414, -0.8112748190760612 0.9532083794474602" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1337.3773246507226 2176.5653641849112) rotate(0 17.5 4.5)"><path d="M0.04649673402309418 0.44384802877902985 L35.988197192549706 1.2666815668344498 L34.985912665724754 8.990287199616432 L-0.8465873152017593 7.383707895874977" stroke="none" stroke-width="0" fill="#000"></path><path d="M-1.8866940587759018 -0.6089111715555191 C13.190968293696642 0.6054665889590979, 26.631805084645748 -1.3407571468502284, 35.58159293234348 -1.9275628477334976 M-0.43818051367998123 0.5884241536259651 C7.896429527550936 -0.8238418560475111, 16.22462324798107 0.05873580165207387, 35.98251836746931 -0.85588388890028 M35.40172212198377 0.12855027839541433 C35.62811806760728 2.892684410512447, 35.670513063296674 5.107440338283777, 34.29997644498944 9.56297608539462 M35.00679400525987 0.3534278992563486 C34.929477049857375 3.2306477319449187, 34.89450029328465 6.786249293759465, 35.41261813007295 8.589756751433015 M36.04884995520115 10.036187514662743 C27.488588105887175 7.714243230596185, 15.413571007549763 8.739119348302484, -1.1534868329763412 9.037085399031639 M35.48350518196821 8.278638787567616 C26.911645527929068 8.818059886619448, 21.077021896839142 8.42382785193622, 0.6250139996409416 9.050776667892933 M-0.06057012006640439 8.419734274595976 C-0.18041477613151077 7.825395655632019, -0.4640528004616499 5.297840941697359, 0.15177264288067815 0.21724449321627615 M0.03208036981523038 8.65153135098517 C0.05397928208112715 6.502076148614288, 0.36054686754941934 3.6170622456818817, 0.4289437707513571 0.14475793875753878" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1344.8773246507226 2168.0653641849112) rotate(0 3 7)"><path d="M0.44384802877902985 0.9881971925497055 L7.26668156683445 -0.014087334275245667 L5.990287199616432 13.15341268479824 L-1.6162921041250229 13.963841781020164" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-0.1826733514666557 -0.2253486469388008 C2.5232852697372437 -0.3191359229385853, 4.267239801585675 0.2310787014663219, 5.421731145679951 -0.41586688309907915 M0.17652724608778952 -0.05330409631133079 C2.047652880102396 0.049211896061897256, 4.602112101763487 0.3210463410615921, 5.743234833329916 -0.11136033162474632 M6.1999670997262 1.0118708834052086 C6.789042288511991 4.929835316538812, 6.553899723738432 6.615107794106008, 6.875740577280521 15.273405908048153 M6.549776732176542 -0.1273611061275005 C5.637047924101353 4.19481799826026, 5.694577778875828 9.395025209337474, 5.361843835562468 13.763786435872316 M6.310856254398823 14.542256085574627 C4.41346735060215 13.746896108537912, 3.490890763700008 13.685419448763133, 0.011125619709491774 13.444788996875285 M5.783591636270285 13.75187440291047 C3.919634724408388 14.208878369033336, 1.7916969470679756 14.216514510810375, 0.01523300036787989 13.712160757929087 M-0.9026355728507041 13.678262923657893 C1.0551976646482943 9.447966909408569, -0.019803908914327664 6.657928158342838, 0.3379358783364297 -0.297216822206974 M-0.5420623429119587 14.10864529684186 C-0.07167169630527495 10.138752960413694, -0.6566879230737686 5.77369537129998, 0.22517901584506028 0.016273856908082918" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1359.8773246507226 2168.0653641849112) rotate(0 3 7)"><path d="M0.9881971925497055 1.2666815668344498 L5.985912665724754 -0.00971280038356781 L5.153412684798241 12.383707895874977 L-0.03615821897983551 12.606611624360085" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-0.2253486469388008 0.19546361714601512 C1.5032554864883423 -0.3701361684501171, 3.932462342083454 -0.5600015191733837, 5.5841331169009205 0.4896859243512154 M-0.05330409631133079 -0.24203304424881933 C1.8521754227578642 -0.012565196156501757, 3.9532642252743244 -0.2920706158876419, 5.888639668375253 -0.07456785812973976 M7.011870883405209 0.8194128528237341 C7.140308762341737 4.480564644932747, 4.973564577847719 8.668329291045666, 7.273405908048153 14.176587392389774 M5.8726388938725 -0.44795388057827945 C5.8203442963957785 4.659594020992518, 6.643964115083218 9.461879929155113, 5.7637864358723165 13.335045992583037 M6.542256085574627 13.643506772816181 C4.082480916380883 13.982055233567953, 2.388054563105106 14.042211245149375, -0.5552110031247138 14.209668166935444 M5.751874402910471 13.929302891343832 C4.287781917303801 13.76775160819292, 2.4033319182693957 13.971951327621937, -0.2878392420709133 13.91194599494338 M-0.3217370763421059 15.029587890207768 C-0.7535297621786594 10.010684061050414, 0.2455127964913846 6.450131367146968, -0.297216822206974 0.24677524715662003 M0.10864529684185986 14.017123853415251 C0.5755476480722427 8.3441521294415, 0.6572653061151504 4.049268021434545, 0.016273856908082918 0.1553468100726605" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(1353.3773246507226 2184.5653641849112) rotate(0 0.66275480017066 12.672529354691505)"><path d="M0.6515453904867172 -1.2524558156728745 C-1.2725264270231127 6.03360120985657, -1.802578280903399 9.51591570597142, 2.132286414504051 26.597514525055885 M-0.8067768141627312 0.07640355080366135 C0.3598242185637355 7.77222840782255, -0.44376953955739734 13.207330573685468, 0.25144047290086746 26.283067397773266" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(1343.8773246507226 2183.5653641849112) rotate(0 -0.32747064530849457 13.575839783996344)"><path d="M-1.2524558156728745 -1.294678345322609 C0.6112074511498213 5.61833264861256, -1.2218312041461468 16.725706270672383, 0.5975145250558853 27.123638972640038 M0.07640355080366135 0.07580084353685379 C1.1121890852600336 9.195737625323238, -0.06210917994379994 19.85064961727709, 0.28306739777326584 28.446357913315296" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(1363.3773246507226 2185.0653641849112) rotate(0 0.3258397839963436 13.629220619797707)"><path d="M-1.294678345322609 0.581592932343483 C-1.4508279721811415 5.315438725464046, 2.5026841283217074 13.491444444693625, 0.6236389726400375 26.67684830725193 M0.07580084353685379 0.9825183674693108 C-0.6382640246674418 6.8245680226758125, 0.39240828897804025 14.175751707218588, 1.9463579133152962 25.64283364266157" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(1372.3773246507226 2193.0653641849112) rotate(0 -16.43732399493456 -0.6023989655077457)"><path d="M0.581592932343483 -1.9275628477334976 C-12.693850107491016 1.4121910957992077, -22.517739802598953 -1.096456346064806, -32.82315169274807 -0.35536064207553864 M0.9825183674693108 -0.85588388890028 C-7.8281599372625355 -0.22278724029660224, -15.130850265920163 0.47213020011782647, -33.85716635733843 0.7227649167180061" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(1371.8773246507226 2202.0653641849112) rotate(0 -18.60562226548791 0.0995359756052494)"><path d="M-1.9275628477334976 -1.386222943663597 C-6.919766509011389 0.43957846209406853, -17.973993482664227 1.7562894535064697, -36.35536064207554 -0.6135536283254623 M-0.85588388890028 -0.3712011054158211 C-11.322854301556944 0.4444143651425838, -21.702989644035696 1.1118209651112556, -35.277235083281994 1.585294894874096" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(919.1800970778143 2588.468754522708) rotate(0 412 242.19444444444457)"><path d="M0 0 C280.227407926321 0, 560.454815852642 0, 824 0 M0 0 C238.9694912016392 0, 477.9389824032784 0, 824 0 M824 0 C824 136.2877507086844, 824 272.5755014173688, 824 484.38888888888914 M824 0 C824 153.1982566141835, 824 306.396513228367, 824 484.38888888888914 M824 484.38888888888914 C619.1304369986058 484.38888888888914, 414.26087399721143 484.38888888888914, 0 484.38888888888914 M824 484.38888888888914 C639.4241226136685 484.38888888888914, 454.84824522733686 484.38888888888914, 0 484.38888888888914 M0 484.38888888888914 C0 332.7260584450846, 0 181.06322800128004, 0 0 M0 484.38888888888914 C0 361.3100231517936, 0 238.23115741469806, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1012.180097077814 2658.468754522708) rotate(0 25 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Stock</text></g><g transform="translate(1049.5967637444805 2842.6195481735012) rotate(0 227.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">current stock will change from 15 to 17 after update</text></g><g transform="translate(1009.2526079003255 2961.9681914365974) rotate(0 288.5 28.5)"><path d="M0 0 C210.21055428311226 0, 420.4211085662245 0, 576.9999999999999 0 M0 0 C145.5924633927643 0, 291.1849267855286 0, 576.9999999999999 0 M576.9999999999999 0 C576.9999999999999 13.76067228242755, 576.9999999999999 27.5213445648551, 576.9999999999999 57 M576.9999999999999 0 C576.9999999999999 14.453476584702731, 576.9999999999999 28.906953169405462, 576.9999999999999 57 M576.9999999999999 57 C439.1269875355064 57, 301.2539750710129 57, 0 57 M576.9999999999999 57 C399.0728687815367 57, 221.14573756307357 57, 0 57 M0 57 C0 35.215562392026186, 0 13.431124784052372, 0 0 M0 57 C0 44.99653309509158, 0 32.99306619018316, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1504.252607900325 2961.9681914365974) rotate(0 41 29)"><path d="M0 0 C25.931014920771123 0, 51.862029841542245 0, 82 0 M0 0 C21.203527615964415 0, 42.40705523192883 0, 82 0 M82 0 C82 20.769845850765705, 82 41.53969170153141, 82 58 M82 0 C82 15.434329311549666, 82 30.868658623099332, 82 58 M82 58 C60.65659751743078 58, 39.313195034861565 58, 0 58 M82 58 C54.86310951858759 58, 27.726219037175177 58, 0 58 M0 58 C0 37.05103646963835, 0 16.102072939276695, 0 0 M0 58 C0 43.39726181775331, 0 28.794523635506625, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(1543.252607900325 2973.9681914365974) rotate(0 0 17)"><path d="M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34 M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1543.252607900325 2973.9681914365974) rotate(0 0 17)"><path d="M-5.814342436536368 18.025225446639556 C-4.479791978043323 21.69187269647201, -3.1452415195502788 25.358519946304465, 0 34 M-5.814342436536368 18.025225446639556 C-4.092619901678256 22.755619233728396, -2.370897366820143 27.486013020817232, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1543.252607900325 2973.9681914365974) rotate(0 0 17)"><path d="M5.814342436536368 18.025225446639556 C4.479791978043323 21.69187269647201, 3.1452415195502788 25.358519946304465, 0 34 M5.814342436536368 18.025225446639556 C4.092619901678256 22.755619233728396, 2.370897366820143 27.486013020817232, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(1040.238523322765 2977.9681914365974) rotate(0 35.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">address</text></g><g transform="translate(924.8979747308113 2517.6019687952994) rotate(0 275 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"># updating product: updating stock</text></g><g transform="translate(1060.2653209606888 2913.4520033282333) rotate(0 54 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">next restock</text></g><g transform="translate(1414.979606674974 2904.6662890425177) rotate(0 36 23)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.0694736183042561 4.8667236839697, 2.4004040606699606 3.335663350863511, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.441522668299273 4.438730210918843, 3.1445021606599943 2.4796764047617965, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C2.449943352066549 9.375687261948018, 4.766741323265487 6.71051606996703, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C3.270109001809981 8.432194609795282, 6.407072622752351 4.823530765661556, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C4.9077817690326295 12.645279943839396, 9.943874981259098 6.851917416673896, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C5.511206114358018 11.951119640829049, 11.150723671909875 5.4635968106532005, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C7.673260726100951 15.56097266761675, 15.08023069046668 7.040228427375489, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C8.553656316296054 14.54819339479961, 16.841021870856885 5.014669881741206, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C9.240123310904831 19.855515798424975, 18.47541268413589 9.231530671916044, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C8.74180051347356 20.428770601187903, 17.478767089273347 10.378040277441904, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C7.938773350425098 27.449560026522423, 16.134169587237874 18.021835111035053, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C7.911517967119886 27.48091375840344, 16.07965882062745 18.084542574797084, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C14.102280369671952 26.456268620719165, 28.06658142080252 10.392177862575423, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C11.953988300397254 28.927595946696226, 23.769997282253126 15.334832514529545, 36.877284942009794 0.25662288638767805 M1.1886405524609494 47.40872423549325 C13.63346182153386 33.0925950140397, 26.07828309060677 18.776465792586155, 42.520359378862906 -0.13797931854138312 M1.1886405524609494 47.40872423549325 C13.834373281759817 32.861472817547124, 26.480106011058684 18.314221399600996, 42.520359378862906 -0.13797931854138312 M6.831714989314069 47.014122030564195 C19.934335677402537 31.941281139186813, 33.03695636549101 16.86844024780943, 47.50737478672552 0.22212805675232872 M6.831714989314069 47.014122030564195 C19.423769074466428 32.52862082898667, 32.01582315961879 18.043119627409144, 47.50737478672552 0.22212805675232872 M11.818730397176676 47.3742294058579 C26.401377920165906 30.59881240177138, 40.98402544315514 13.823395397684855, 53.15044922357863 -0.1724741481767289 M11.818730397176676 47.3742294058579 C23.885941807439863 33.49249063623425, 35.95315321770305 19.61075186661059, 53.15044922357863 -0.1724741481767289 M17.461804834029795 46.979627200928846 C33.05256944474344 29.04450414834451, 48.64333405545709 11.109381095760178, 58.13746463144125 0.1876332271169865 M17.461804834029795 46.979627200928846 C33.514412316278964 28.51321469982981, 49.567019798528136 10.046802198730774, 58.13746463144125 0.1876332271169865 M22.448820241892403 47.33973457622256 C37.292288074414145 30.264278128088236, 52.135755906935884 13.18882167995391, 63.78053906829436 -0.20696897781207468 M22.448820241892403 47.33973457622256 C33.45126223718552 34.68287290255567, 44.453704232478636 22.02601122888878, 63.78053906829436 -0.20696897781207468 M28.091894678745525 46.9451323712935 C38.520159473394585 34.94878600939413, 48.94842426804365 22.952439647494757, 68.76755447615697 0.1531383974816336 M28.091894678745525 46.9451323712935 C43.84148948937288 28.827296074615823, 59.59108430000025 10.70945977793815, 68.76755447615697 0.1531383974816336 M33.07891008660813 47.30523974658722 C47.34793195115798 30.89060779166325, 61.61695381570783 14.47597583673928, 73.09851085502908 1.2679553529981291 M33.07891008660813 47.30523974658722 C48.8976173679153 29.107898647094505, 64.71632464922247 10.91055754760179, 73.09851085502908 1.2679553529981291 M38.72198452346125 46.91063754165816 C49.905834415763785 34.045089954451235, 61.08968430806631 21.17954236724431, 73.49311305995813 6.911029789851241 M38.72198452346125 46.91063754165816 C46.02654066942349 38.507706922571145, 53.33109681538572 30.10477630348413, 73.49311305995813 6.911029789851241 M43.70899993132386 47.27074491695187 C51.65369853686655 38.13141463624275, 59.59839714240923 28.99208435553363, 73.23165623589668 13.30881380692713 M43.70899993132386 47.27074491695187 C54.28661543049228 35.10259022297723, 64.8642309296607 22.93443552900258, 73.23165623589668 13.30881380692713 M49.35207436817697 46.87614271202281 C55.18257527926562 40.168918665633115, 61.013076190354276 33.46169461924342, 72.97019941183524 19.706597824003016 M49.35207436817697 46.87614271202281 C56.40510873276693 38.76255480395442, 63.45814309735688 30.64896689588603, 72.97019941183524 19.706597824003016 M54.339089776039586 47.23625008731652 C60.20503176150179 40.48825574864951, 66.070973746964 33.7402614099825, 73.3648016167643 25.34967226085613 M54.339089776039586 47.23625008731652 C60.938011574559695 39.64505892857694, 67.5369333730798 32.05386776983735, 73.3648016167643 25.34967226085613 M59.9821642128927 46.84164788238747 C65.06426690316256 40.99535750524812, 70.14636959343241 35.149067128108776, 73.10334479270284 31.747456277932027 M59.9821642128927 46.84164788238747 C62.61570580044832 43.81210484096082, 65.24924738800394 40.78256179953418, 73.10334479270284 31.747456277932027 M64.96917962075531 47.20175525768118 C68.15218823756568 43.54012270499029, 71.33519685437605 39.87849015229939, 73.49794699763191 37.39053071478514 M64.96917962075531 47.20175525768118 C67.22962937584751 44.60140527331265, 69.49007913093969 42.00105528894413, 73.49794699763191 37.39053071478514 M69.95619502861793 47.561862632974886 C71.22166828660232 46.106102176806594, 72.48714154458672 44.6503417206383, 73.23649017357046 43.78831473186103 M69.95619502861793 47.561862632974886 C71.19178496651935 46.140479004132914, 72.42737490442077 44.71909537529095, 73.23649017357046 43.78831473186103" stroke="#4c6ef5" stroke-width="0.5" fill="none"></path><path d="M0 0 C15.607046788930894 0, 31.21409357786179 0, 72 0 M0 0 C27.95016422867775 0, 55.9003284573555 0, 72 0 M72 0 C72 15.406367994844913, 72 30.812735989689827, 72 46 M72 0 C72 16.16315798610449, 72 32.32631597220898, 72 46 M72 46 C57.02690897583962 46, 42.05381795167923 46, 0 46 M72 46 C54.47378405928612 46, 36.947568118572235 46, 0 46 M0 46 C0 36.32309472411871, 0 26.64618944823742, 0 0 M0 46 C0 33.51145796924829, 0 21.022915938496585, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1045.6130286524176 2712.5638470792755) rotate(0 40 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">incoming</text></g><g transform="translate(1232.1023444624875 2713.6927169821456) rotate(0 5.5 11.5)"><text x="5.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">3</text></g><g transform="translate(1045.6130286524176 2763.5638470792755) rotate(0 42 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">notify lost</text></g><g transform="translate(1232.1023444624875 2770.6927169821456) rotate(0 5.5 11.5)"><text x="5.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">1</text></g><g transform="translate(1198.1076865574526 2702.6282820307106) rotate(0 52.5 20.5)"><path d="M0 0 C26.49429576471448 0, 52.98859152942896 0, 105 0 M0 0 C25.34860683605075 0, 50.6972136721015 0, 105 0 M105 0 C105 10.39636035040021, 105 20.79272070080042, 105 41 M105 0 C105 9.796869169920683, 105 19.593738339841366, 105 41 M105 41 C72.62157924100757 41, 40.24315848201513 41, 0 41 M105 41 C64.87077282741666 41, 24.741545654833317 41, 0 41 M0 41 C0 32.36592731401324, 0 23.731854628026486, 0 0 M0 41 C0 29.648827327042817, 0 18.297654654085633, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1199.1076865574526 2759.6282820307106) rotate(0 51 22.5)"><path d="M0 0 C26.37511971741915 0, 52.7502394348383 0, 102 0 M0 0 C36.526280634105206 0, 73.05256126821041 0, 102 0 M102 0 C102 11.974910672754051, 102 23.949821345508102, 102 45 M102 0 C102 11.71284282580018, 102 23.42568565160036, 102 45 M102 45 C68.24435574263333 45, 34.48871148526668 45, 0 45 M102 45 C65.15871930867434 45, 28.31743861734867 45, 0 45 M0 45 C0 33.67028934136033, 0 22.340578682720658, 0 0 M0 45 C0 35.718918677419424, 0 26.437837354838848, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1431.979606674974 2915.1662890425177) rotate(0 21.5 11.5)"><text x="21.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">clear</text></g><g transform="translate(1515.162496303048 2904.5895592402812) rotate(0 36 23)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.3753640436643175 4.514837002564089, 3.0121849113900834 2.6318899880522895, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C0.8493351942651193 5.119963972199745, 1.9601272125916869 3.842143927323601, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C3.034463156220709 8.70327414585406, 5.935780931573807 5.365689837779114, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C2.961258922947706 8.78748598308616, 5.789372465027801 5.534113512243313, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C5.4253787671312494 12.049852709554312, 10.979068977456338 5.661062948103725, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C5.178774409341544 12.333538571838613, 10.485860261876928 6.22843467267233, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C7.788121109505969 15.428840911306326, 15.309951457276716 6.775964914754638, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C5.330556112387134 18.255946042684027, 10.394821463039046 12.430175177510039, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C6.3299650457229895 23.203269926703264, 12.655096153772206 15.92703892847263, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C8.944233705451841 20.19589785256318, 17.88363347322991 9.912294780192461, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C11.134114539684509 23.77374047210639, 22.524851965756696 10.670196002202985, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C7.814464994959845 27.59256043140325, 15.885552876307369 18.30783592079671, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C12.337943974365544 28.48590546958986, 24.537908630189705 14.451451560316809, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C13.741365245342406 26.87145397743612, 27.34475117214343 11.22254857600933, 36.877284942009794 0.25662288638767805 M1.1886405524609494 47.40872423549325 C16.215279177930732 30.122553894025874, 31.24191780340052 12.836383552558495, 42.520359378862906 -0.13797931854138312 M1.1886405524609494 47.40872423549325 C9.581212113384062 37.75417505646579, 17.973783674307175 28.099625877438324, 42.520359378862906 -0.13797931854138312 M6.831714989314069 47.014122030564195 C17.757773431649383 34.445129583051255, 28.6838318739847 21.876137135538308, 47.50737478672552 0.22212805675232872 M6.831714989314069 47.014122030564195 C18.475860205318625 33.6190652449789, 30.120005421323178 20.2240084593936, 47.50737478672552 0.22212805675232872 M11.818730397176676 47.3742294058579 C27.21453877819911 29.663377840701255, 42.61034715922155 11.952526275544606, 53.15044922357863 -0.1724741481767289 M11.818730397176676 47.3742294058579 C24.78789339673942 32.45491402306125, 37.75705639630217 17.535598640264602, 53.15044922357863 -0.1724741481767289 M17.461804834029795 46.979627200928846 C32.95671218411056 29.154775312579325, 48.45161953419132 11.329923424229804, 58.13746463144125 0.1876332271169865 M17.461804834029795 46.979627200928846 C28.098486788354222 34.7435243230162, 38.73516874267865 22.50742144510356, 58.13746463144125 0.1876332271169865 M22.448820241892403 47.33973457622256 C32.99473548210508 35.20804685865133, 43.54065072231776 23.076359141080104, 63.78053906829436 -0.20696897781207468 M22.448820241892403 47.33973457622256 C35.35900949885364 32.488260723770274, 48.26919875581487 17.636786871317987, 63.78053906829436 -0.20696897781207468 M28.091894678745525 46.9451323712935 C39.758227506288875 33.52455165836228, 51.424560333832225 20.103970945431055, 68.76755447615697 0.1531383974816336 M28.091894678745525 46.9451323712935 C43.60212757494806 29.102650458862083, 59.11236047115059 11.26016854643067, 68.76755447615697 0.1531383974816336 M33.07891008660813 47.30523974658722 C48.00875136482454 30.130422015302933, 62.93859264304095 12.955604284018648, 73.09851085502908 1.2679553529981291 M33.07891008660813 47.30523974658722 C42.69862404602975 36.23902472116566, 52.318338005451366 25.17280969574411, 73.09851085502908 1.2679553529981291 M38.72198452346125 46.91063754165816 C48.85826304400882 35.25018296482732, 58.9945415645564 23.589728387996466, 73.49311305995813 6.911029789851241 M38.72198452346125 46.91063754165816 C47.190995580249954 37.16815478152302, 55.66000663703865 27.425672021387886, 73.49311305995813 6.911029789851241 M43.70899993132386 47.27074491695187 C54.787307700832244 34.52660965343837, 65.86561547034063 21.782474389924868, 73.23165623589668 13.30881380692713 M43.70899993132386 47.27074491695187 C51.14701488272454 38.71428750442301, 58.585029834125216 30.15783009189416, 73.23165623589668 13.30881380692713 M49.35207436817697 46.87614271202281 C58.51149848727816 36.33943057707068, 67.67092260637935 25.80271844211855, 72.97019941183524 19.706597824003016 M49.35207436817697 46.87614271202281 C57.82154168796805 37.133135081344356, 66.29100900775913 27.390127450665904, 72.97019941183524 19.706597824003016 M54.339089776039586 47.23625008731652 C61.9156957815482 38.52036190461843, 69.49230178705682 29.80447372192035, 73.3648016167643 25.34967226085613 M54.339089776039586 47.23625008731652 C58.40411740517944 42.559970728273505, 62.4691450343193 37.88369136923049, 73.3648016167643 25.34967226085613 M59.9821642128927 46.84164788238747 C63.34098199809981 42.97777001667317, 66.69979978330691 39.11389215095886, 73.10334479270284 31.747456277932027 M59.9821642128927 46.84164788238747 C64.5650515727087 41.569639049802646, 69.14793893252468 36.29763021721783, 73.10334479270284 31.747456277932027 M64.96917962075531 47.20175525768118 C67.23811460726664 44.59164413116013, 69.50704959377795 41.98153300463908, 73.49794699763191 37.39053071478514 M64.96917962075531 47.20175525768118 C67.56727982892488 44.21298285940858, 70.16538003709445 41.22421046113598, 73.49794699763191 37.39053071478514 M69.95619502861793 47.561862632974886 C70.82153976332255 46.566397388815645, 71.68688449802717 45.570932144656396, 73.23649017357046 43.78831473186103 M69.95619502861793 47.561862632974886 C71.10737221247501 46.23758476955204, 72.2585493963321 44.9133069061292, 73.23649017357046 43.78831473186103" stroke="#4c6ef5" stroke-width="0.5" fill="none"></path><path d="M0 0 C17.131241887807846 0, 34.26248377561569 0, 72 0 M0 0 C16.469169813394547 0, 32.938339626789094 0, 72 0 M72 0 C72 17.891359259188174, 72 35.78271851837635, 72 46 M72 0 C72 16.85603842586279, 72 33.71207685172558, 72 46 M72 46 C50.652469736337665 46, 29.304939472675322 46, 0 46 M72 46 C44.20580386519432 46, 16.41160773038864 46, 0 46 M0 46 C0 34.4678519949317, 0 22.935703989863395, 0 0 M0 46 C0 30.86363368183374, 0 15.727267363667483, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1523.662496303048 2915.0895592402812) rotate(0 25 11.5)"><text x="25" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">never</text></g><g transform="translate(1196.0885167112117 2909.119093132542) rotate(0 71.39795918367349 18.459183673469397)"><path d="M-1.1418243795633316 -1.0046259015798569 L144.4990232060759 -1.426329717040062 L144.43414712651656 35.85880122166503 L1.6835669130086899 36.37682518940795" stroke="none" stroke-width="0" fill="#fff"></path><path d="M-0.3727961629629135 0.7564176172018051 C36.729751035495084 -0.37391743593526106, 72.55191798492964 0.4629704005210378, 141.37068775995658 -1.3066493421792984 M0.16271203011274338 0.27240557223558426 C33.05778231309082 -1.5164845041489725, 67.19790111901811 -0.5159411482072, 143.68534429325746 -0.5211303755640984 M141.7684805761187 0.5503796190023422 C142.3601679568647 11.758133697312084, 142.19128701738106 24.685477009020264, 144.12463072641776 35.19265205245841 M142.03591687931703 -0.03182869404554367 C142.0532299560963 14.845505480909212, 142.76549711651194 29.45545226572725, 142.76085312618898 36.28411140870679 M143.05794600351737 37.254392927702554 C102.65255512438566 38.71467735192449, 63.151354308730504 38.18086816689642, 1.720610037446022 36.485484903868326 M142.3368285442798 36.1935180706941 C98.39024040980306 35.308574170508216, 51.90110314202552 35.750081271567176, -0.49301130324602127 36.76974835824598 M-1.9394584745168686 37.318343943174966 C-0.6244689786692664 25.33277080455906, -1.769820865418534 14.929091586841594, 0.5810288339853287 -1.157154694199562 M0.27907007187604904 37.90980687570203 C-0.48869153535335613 27.076435881016785, 0.3116646143201058 17.86483765244482, -0.028601713478565216 -0.6333113238215446" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1230.736475894885 2915.5782768060126) rotate(0 5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(1261.236475894885 2915.0782768060126) rotate(0 5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(1350.236475894885 2908.0782768060126) rotate(0 17.75 17.75)"><path d="M-1.426329717040062 1.6382287591695786 L34.440433874726295 1.6835669130086899 L34.958457842469215 34.71851383149624 L0.8811601549386978 33.981839045882225" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-1.1716939359903336 1.1620158106088638 C9.653480711206795 -1.6089075982198118, 18.66992427930236 -1.4540733277425169, 36.198420867323875 1.4736865907907486 M-0.46430235356092453 -0.33890873938798904 C11.763868709281088 1.1416969546303153, 21.93412503823638 0.767912174127996, 36.01372999697924 0.26068418473005295 M34.278960570693016 -0.794292077422142 C34.32482313815504 10.155010279640555, 33.87197708789259 19.649615981429815, 33.65919195115566 33.854674234986305 M35.58365911990404 0.30937688797712326 C35.42046035733074 7.916929476335645, 34.85444487538189 15.735595040768386, 34.934196658432484 35.606899194419384 M37.1436623185873 36.723780527710915 C25.494754079356788 37.27222864385694, 12.836919448524714 35.88320915456861, -1.7926498800516129 34.497640028595924 M34.60587138682604 35.017713479697704 C26.027147359773515 35.291196866966786, 17.310918755084277 35.79700498197228, -0.285099558532238 35.459210090339184 M-0.46284259855747223 33.624925032258034 C0.18523628171533346 28.873567626252772, -1.2281505400314927 20.07083387747407, 1.4420164674520493 -0.423099622130394 M-0.6386323496699333 36.077849082648754 C-0.9988924947008491 23.83069953136146, -0.9852723565325141 11.647690299898386, -0.5023129507899284 0.8515524193644524" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1351.236475894885 2909.0782768060126) rotate(0 17.5 4.5)"><path d="M1.6382287591695786 -1.0595661252737045 L36.68356691300869 -0.5415421575307846 L34.21851383149624 9.881160154938698 L-1.518160954117775 9.852583780884743" stroke="none" stroke-width="0" fill="#000"></path><path d="M1.1620158106088638 -0.33480609953403473 C10.398500222712755 -1.10160290338099, 22.37706532329321 0.9034673061221838, 36.47368659079075 0.32542406022548676 M-0.33890873938798904 0.5362410023808479 C12.342845428735018 -0.35862455181777475, 23.422480151057243 0.6762358207255602, 35.26068418473005 -0.5137188956141472 M34.64256856516003 -0.5727911598980426 C35.56977706037462 2.1710989460349084, 35.87051556192338 5.0669780351221565, 34.25960340574384 8.315998660773039 M35.13921959958971 -0.030708205327391602 C34.947960516959434 2.3859390031546357, 34.88796239808202 5.08809684701264, 35.04810463748872 9.058956218138338 M36.223780527710915 10.109853133559227 C25.632565271109343 8.854758462682366, 13.15550101548433 7.4949910257011645, -1.0023599714040756 8.081820353865623 M34.517713479697704 8.547378487884998 C26.54396116361022 8.538435996696354, 19.086741745471954 8.401955426856876, -0.04078990966081619 8.030270762741566 M-0.8437837354838849 9.115304457396268 C0.29430051393806944 5.599290919303893, -0.42357212953269485 3.888928473740816, -0.1903948299586773 0.25116306468844407 M0.2600320871919393 8.708880842104554 C0.007154864966869359 5.12271432839334, -0.23688484936952597 1.5893680203706027, 0.38319858871400353 -0.320924186334014" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1358.736475894885 2900.5782768060126) rotate(0 3 7)"><path d="M-1.0595661252737045 1.6835669130086899 L5.458457842469215 -0.7814861685037613 L6.881160154938698 12.481839045882225 L0.8525837808847427 13.071687087416649" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-0.10044182986021044 -0.42756918221712115 C1.7184451818466187 -0.41597937539219854, 4.430406229197979 0.40724550291895867, 6.097627218067646 0.16344334334135058 M0.16087230071425435 0.26682777777314187 C1.2172873176634313 0.1750268679857254, 2.9013718597590925 0.09853977978229525, 5.845884331315756 0.08255694285035131 M5.108991529047489 0.9300986513495446 C4.706526533812285 5.160126301646233, 4.6259616057574755 6.372696371376515, 4.93599791675806 13.955439828336239 M5.952231680601836 -0.024545668810606047 C5.5677331200242035 3.5180775426328186, 5.615649937689304 7.3467366732656965, 6.091709672659635 14.117608953267336 M6.332955940067768 14.516183011233807 C3.982892552018165 14.136190580278635, 1.6877196058630939 13.736005424410104, -0.27545389384031294 13.565090434253216 M5.8642135463655 13.852096609026194 C3.6750624664127827 13.974901852309705, 1.3537664584815499 13.958825835883617, -0.2909187711775303 14.059996489435434 M0.17936248928308496 14.40672018378973 C-0.7776093040406704 9.600835561752318, 1.0418105091154577 6.325442577898501, 0.3906981006264687 1.3880153402686117 M-0.4528520233929157 13.979978800565004 C-0.3539093977212906 9.711871360987423, -0.26221053659915916 6.819106481224297, -0.4992154009640216 0.5733800657093524" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1373.7364758948847 2900.5782768060126) rotate(0 3 7)"><path d="M1.6835669130086899 -0.5415421575307846 L5.218513831496239 0.8811601549386978 L4.481839045882225 14.852583780884743 L-0.9283129125833511 15.40739668905735" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-0.42756918221712115 -0.3919948026537895 C1.0673729181289673 0.21957044318318364, 3.3390896156430245 0.10767140105366711, 6.163443343341351 -0.4263735696673393 M0.26682777777314187 -0.1563391126692295 C1.6761109314858915 0.1219445389509201, 3.1210424311459066 -0.186290128827095, 6.082556942850351 -0.09381167069077492 M6.930098651349544 -1.2080007061362266 C7.342313652783632 2.0567067652940754, 4.792671519070863 5.626542715728283, 5.955439828336239 13.435953618586064 M5.975454331189394 -0.4439791567623615 C5.925436688363552 3.921060428768396, 6.118142200410366 8.725955208390952, 6.117608953267336 14.10178316757083 M6.516183011233807 13.870135267078876 C3.8063784688711166 13.495500629991293, 1.1130946174263954 13.757841700166464, -0.4349095657467842 14.48035183697939 M5.852096609026193 13.955414303392171 C4.740316211432219 13.88731284171343, 3.460717362910509 13.68192393809557, 0.05999648943543434 13.890541537851096 M0.40672018378973007 13.189991714060307 C-0.578715347200632 11.133401346206664, -0.16491448774933815 6.638677738606929, 1.3880153402686117 -0.3115098938345908 M-0.020021199434995696 13.556682073324918 C-0.48053740441799164 10.342466223984957, 0.5151878219842909 6.888955178111791, 0.5733800657093524 -0.37084814384579656" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(1367.236475894885 2917.0782768060126) rotate(0 -0.5165169888082914 12.3095419742167)"><path d="M-1.3066493421792984 -1.2703963369131088 C0.8331094544008374 10.96692061636597, 0.6391630425676703 19.527716119103133, -0.9212452322244644 25.57139529287815 M-0.5211303755640984 0.5156411454081535 C0.7888884256407619 7.308128895722331, -0.10550590392202136 14.37452636111528, 0.18729443103075027 25.889480285346508" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(1357.736475894885 2916.0782768060126) rotate(0 -0.308343032559776 14.058291979134083)"><path d="M-1.2703963369131088 0.6984208673238754 C1.415784153267741 8.259962144233288, 0.6285385544598103 14.44456431243569, -0.42860470712184906 27.322182521224022 M0.5156411454081535 0.5137299969792366 C0.6865354941040278 9.390361562930048, 0.8778531689941884 19.492849696241322, -0.11051971465349197 27.60285396128893" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(1377.2364758948847 2917.5782768060126) rotate(0 0.5400990881577172 13.416583094745874)"><path d="M0.6984208673238754 1.4736865907907486 C0.5019339735433459 6.387170092575253, -0.9016276144608855 10.74658521655947, 0.8221825212240219 26.572482004761696 M0.5137299969792366 0.26068418473005295 C-0.06319325249642127 10.185491303391755, 0.721233963035047 19.217817890308798, 1.102853961288929 24.863565377891064" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(1386.2364758948847 2925.5782768060126) rotate(0 -16.581374015659094 0.6196436536490637)"><path d="M1.4736865907907486 0.32542406022548676 C-7.433884973824025 -1.3025136847794057, -16.885996943712236 -0.5590859313309193, -32.927517995238304 1.7788518518209457 M0.26068418473005295 -0.5137188956141472 C-8.152966913580896 -0.13803736999630928, -17.466833160817625 -0.22247783973813057, -34.636434622108936 0.664356179535389" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(1385.7364758948847 2934.5782768060126) rotate(0 -17.505109880119562 0.33789916107161844)"><path d="M0.32542406022548676 0.5448111444711685 C-9.93103972144425 -0.42686093762516975, -17.70089856155217 1.8107059574127198, -34.221148148179054 -0.042260751128196716 M-0.5137188956141472 0.2751898095011711 C-12.96387639246881 -0.16510929360985754, -25.704624985679985 0.16053991347551344, -35.33564382046461 0.1371423527598381" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(1830.430097077814 2584.8713272638206) rotate(0 412 257.81944444444457)"><path d="M0 0 C289.3018495619297 0, 578.6036991238594 0, 824 0 M0 0 C266.4378617227078 0, 532.8757234454156 0, 824 0 M824 0 C824 168.13916297101736, 824 336.2783259420347, 824 515.6388888888891 M824 0 C824 103.9498607670889, 824 207.8997215341778, 824 515.6388888888891 M824 515.6388888888891 C509.1749795854091 515.6388888888891, 194.34995917081824 515.6388888888891, 0 515.6388888888891 M824 515.6388888888891 C495.227893358469 515.6388888888891, 166.45578671693795 515.6388888888891, 0 515.6388888888891 M0 515.6388888888891 C0 387.63720168262324, 0 259.63551447635734, 0 0 M0 515.6388888888891 C0 312.98472778310804, 0 110.330566677327, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1923.430097077814 2654.8713272638206) rotate(0 25 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Stock</text></g><g transform="translate(1957.8467637444805 2719.272120914614) rotate(0 31 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">current</text></g><g transform="translate(1909.2526079003255 3004.620764177708) rotate(0 288.5 28.5)"><path d="M0 0 C192.039151353389 0, 384.078302706778 0, 576.9999999999999 0 M0 0 C136.73794285580513 0, 273.47588571161026 0, 576.9999999999999 0 M576.9999999999999 0 C576.9999999999999 22.734716738015415, 576.9999999999999 45.46943347603083, 576.9999999999999 57 M576.9999999999999 0 C576.9999999999999 19.196387576311828, 576.9999999999999 38.392775152623656, 576.9999999999999 57 M576.9999999999999 57 C404.0372541241347 57, 231.07450824826947 57, 0 57 M576.9999999999999 57 C368.86377132609476 57, 160.72754265218964 57, 0 57 M0 57 C0 41.1177114598453, 0 25.235422919690603, 0 0 M0 57 C0 44.01384368017316, 0 31.027687360346317, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2404.252607900325 3004.620764177708) rotate(0 41 29)"><path d="M0 0 C26.443931220471864 0, 52.88786244094373 0, 82 0 M0 0 C24.761952497065067 0, 49.523904994130135 0, 82 0 M82 0 C82 18.225900404155254, 82 36.45180080831051, 82 58 M82 0 C82 14.270743449032308, 82 28.541486898064615, 82 58 M82 58 C64.16376731544733 58, 46.32753463089466 58, 0 58 M82 58 C50.749854277074334 58, 19.49970855414867 58, 0 58 M0 58 C0 42.38057781010866, 0 26.761155620217323, 0 0 M0 58 C0 43.396501176059246, 0 28.793002352118492, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(2443.252607900325 3016.620764177708) rotate(0 0 17)"><path d="M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34 M0 0 C0 5.666666666666667, 0 28.333333333333332, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2443.252607900325 3016.620764177708) rotate(0 0 17)"><path d="M-5.814342436536368 18.025225446639556 C-3.672683048188459 23.909386256288435, -1.5310236598405504 29.79354706593731, 0 34 M-5.814342436536368 18.025225446639556 C-4.438116949352489 21.8063738967552, -3.0618914621686106 25.587522346870845, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2443.252607900325 3016.620764177708) rotate(0 0 17)"><path d="M5.814342436536368 18.025225446639556 C3.672683048188459 23.909386256288435, 1.5310236598405504 29.79354706593731, 0 34 M5.814342436536368 18.025225446639556 C4.438116949352489 21.8063738967552, 3.0618914621686106 25.587522346870845, 0 34" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(1940.238523322765 3020.620764177708) rotate(0 35.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">address</text></g><g transform="translate(2138.8360795545505 2714.400990817485) rotate(0 11 11.5)"><text x="11" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">15</text></g><g transform="translate(1960.2653209606888 2956.104576069344) rotate(0 54 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">next restock</text></g><g transform="translate(2314.979606674974 2947.3188617836304) rotate(0 36 23)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.6911573955638532 4.151558307328436, 3.643771615189155 1.9053325975809834, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C0.7997554922365635 5.176998895052827, 1.8609678085345753 3.956213773029765, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C4.062912716240784 7.520178263586619, 7.992680051613957 2.999498073244231, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C4.049132298871088 7.536030820367036, 7.965119216874566 3.0312031868050653, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C4.8136656135422236 12.75354819572466, 9.755642670278286 7.068453920444423, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C3.449655413071555 14.322662437473312, 7.027622269336949 10.206682403941727, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C5.600209395927803 17.945745424395433, 10.934128030120384 11.80977394093285, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C7.778368749644854 15.440059717986403, 15.290446737554486 6.798402528114792, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C9.557007825434983 19.49098186417192, 19.109181713196193 8.50246280340994, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C8.269400297414974 20.97220488530608, 16.533966657156174 11.46490884567826, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C12.381592583292894 22.33868114203743, 25.019808052973467 7.800077342065066, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C10.375073706732453 24.646917066125155, 21.006770299852583 12.416549190240513, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C12.866313075108254 27.878086348743665, 25.594646831675124 13.235813318624427, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C9.116221042623618 32.19207374708522, 18.094462766705853 21.863788115307525, 36.877284942009794 0.25662288638767805 M1.1886405524609494 47.40872423549325 C16.041378277651415 30.322603995694497, 30.89411600284188 13.23648375589574, 42.520359378862906 -0.13797931854138312 M1.1886405524609494 47.40872423549325 C10.575569958155524 36.61029720636832, 19.9624993638501 25.811870177243396, 42.520359378862906 -0.13797931854138312 M6.831714989314069 47.014122030564195 C21.993421283387114 29.57257411029863, 37.15512757746016 12.131026190033062, 47.50737478672552 0.22212805675232872 M6.831714989314069 47.014122030564195 C19.326236998072215 32.64081864836124, 31.82075900683036 18.26751526615828, 47.50737478672552 0.22212805675232872 M11.818730397176676 47.3742294058579 C20.41523953522264 37.485076881063115, 29.0117486732686 27.59592435626833, 53.15044922357863 -0.1724741481767289 M11.818730397176676 47.3742294058579 C24.005080671428516 33.3554370510295, 36.19143094568036 19.33664469620109, 53.15044922357863 -0.1724741481767289 M17.461804834029795 46.979627200928846 C27.30168755303564 35.66013699022456, 37.141570272041484 24.340646779520274, 58.13746463144125 0.1876332271169865 M17.461804834029795 46.979627200928846 C29.966561935749773 32.59454969113763, 42.471319037469755 18.20947218134641, 58.13746463144125 0.1876332271169865 M22.448820241892403 47.33973457622256 C34.096683995671754 33.94040010226008, 45.7445477494511 20.5410656282976, 63.78053906829436 -0.20696897781207468 M22.448820241892403 47.33973457622256 C34.61132520278209 33.34837311654626, 46.77383016367178 19.35701165686996, 63.78053906829436 -0.20696897781207468 M28.091894678745525 46.9451323712935 C37.873037623192126 35.69321454148944, 47.65418056763873 24.44129671168539, 68.76755447615697 0.1531383974816336 M28.091894678745525 46.9451323712935 C42.805641640247245 30.01890271493779, 57.51938860174897 13.092673058582086, 68.76755447615697 0.1531383974816336 M33.07891008660813 47.30523974658722 C41.52728154943033 37.58650012328902, 49.97565301225252 27.867760499990823, 73.09851085502908 1.2679553529981291 M33.07891008660813 47.30523974658722 C45.01406722213595 33.57541204265762, 56.949224357663766 19.84558433872802, 73.09851085502908 1.2679553529981291 M38.72198452346125 46.91063754165816 C50.628924475497925 33.21326999415753, 62.53586442753459 19.5159024466569, 73.49311305995813 6.911029789851241 M38.72198452346125 46.91063754165816 C49.1254441827442 34.94282622382081, 59.52890384202714 22.97501490598346, 73.49311305995813 6.911029789851241 M43.70899993132386 47.27074491695187 C52.9683870680543 36.61903848462857, 62.22777420478474 25.967332052305267, 73.23165623589668 13.30881380692713 M43.70899993132386 47.27074491695187 C52.332436774433255 37.35061561097314, 60.95587361754265 27.430486304994417, 73.23165623589668 13.30881380692713 M49.35207436817697 46.87614271202281 C54.29645130424312 41.188287691380104, 59.24082824030926 35.500432670737396, 72.97019941183524 19.706597824003016 M49.35207436817697 46.87614271202281 C55.52636925090044 39.77342894207139, 61.7006641336239 32.67071517211997, 72.97019941183524 19.706597824003016 M54.339089776039586 47.23625008731652 C61.848158492637964 38.59805466809013, 69.35722720923634 29.95985924886374, 73.3648016167643 25.34967226085613 M54.339089776039586 47.23625008731652 C61.44910340704825 39.05711503129342, 68.55911703805691 30.877979975270318, 73.3648016167643 25.34967226085613 M59.9821642128927 46.84164788238747 C65.10228084440658 40.95162746820704, 70.22239747592046 35.061607054026624, 73.10334479270284 31.747456277932027 M59.9821642128927 46.84164788238747 C63.95140054181702 42.27556380879902, 67.92063687074135 37.70947973521058, 73.10334479270284 31.747456277932027 M64.96917962075531 47.20175525768118 C67.92874239103999 43.7971677475582, 70.88830516132467 40.39258023743522, 73.49794699763191 37.39053071478514 M64.96917962075531 47.20175525768118 C67.98336749725237 43.734328751130384, 70.99755537374942 40.2669022445796, 73.49794699763191 37.39053071478514 M69.95619502861793 47.561862632974886 C71.01105223518607 46.34838822840949, 72.0659094417542 45.134913823844094, 73.23649017357046 43.78831473186103 M69.95619502861793 47.561862632974886 C71.2324011335524 46.093755448755694, 72.50860723848686 44.625648264536494, 73.23649017357046 43.78831473186103" stroke="#4c6ef5" stroke-width="0.5" fill="none"></path><path d="M0 0 C23.49195336699486 0, 46.98390673398972 0, 72 0 M0 0 C20.274025350809097 0, 40.548050701618195 0, 72 0 M72 0 C72 16.314749504625798, 72 32.629499009251596, 72 46 M72 0 C72 17.762838457524776, 72 35.52567691504955, 72 46 M72 46 C46.1160380423069 46, 20.232076084613794 46, 0 46 M72 46 C43.98897323012352 46, 15.97794646024704 46, 0 46 M0 46 C0 36.70909492820501, 0 27.418189856410027, 0 0 M0 46 C0 28.832874299585818, 0 11.665748599171636, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1956.8630286524176 2765.9664198203873) rotate(0 40 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">incoming</text></g><g transform="translate(2143.3523444624875 2767.0952897232573) rotate(0 5.5 11.5)"><text x="5.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">3</text></g><g transform="translate(1956.8630286524176 2816.9664198203873) rotate(0 42 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">notify lost</text></g><g transform="translate(2143.3523444624875 2824.0952897232573) rotate(0 5.5 11.5)"><text x="5.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">1</text></g><g transform="translate(1956.8630286524176 2880.9664198203873) rotate(0 53.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">after update</text></g><g transform="translate(2143.8523444624875 2882.0952897232573) rotate(0 11 11.5)"><text x="11" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">17</text></g><g transform="translate(2109.3576865574523 2756.0308547718223) rotate(0 52.5 20.5)"><path d="M0 0 C31.698343444615606 0, 63.39668688923121 0, 105 0 M0 0 C31.209965955466036 0, 62.41993191093207 0, 105 0 M105 0 C105 11.741622019559145, 105 23.48324403911829, 105 41 M105 0 C105 9.947629534453155, 105 19.89525906890631, 105 41 M105 41 C79.51778180524707 41, 54.03556361049414 41, 0 41 M105 41 C71.71336268261075 41, 38.4267253652215 41, 0 41 M0 41 C0 31.30118932649493, 0 21.602378652989863, 0 0 M0 41 C0 28.524867499619724, 0 16.049734999239444, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2110.3576865574523 2813.0308547718223) rotate(0 51 22.5)"><path d="M0 0 C28.886803181469443 0, 57.773606362938885 0, 102 0 M0 0 C37.173303835093975 0, 74.34660767018795 0, 102 0 M102 0 C102 13.430311616510155, 102 26.86062323302031, 102 45 M102 0 C102 16.05211198702455, 102 32.1042239740491, 102 45 M102 45 C62.9927919074893 45, 23.985583814978597 45, 0 45 M102 45 C75.50919366627932 45, 49.01838733255863 45, 0 45 M0 45 C0 35.4621723331511, 0 25.924344666302204, 0 0 M0 45 C0 31.916056986898184, 0 18.832113973796368, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2331.979606674974 2957.8188617836304) rotate(0 21.5 11.5)"><text x="21.5" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">clear</text></g><g transform="translate(2415.162496303048 2947.242131981392) rotate(0 36 23)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.4970441935106777 4.374860002394918, 3.255545211082804 2.3519359877139463, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.0193498443811764 4.924384489941499, 2.300156512823801 3.450984962807109, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C3.695068028794355 7.943335170789077, 7.256990676721099 3.8458118876491483, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C3.2546144924552527 8.450019003842351, 6.376083604042894 4.8591795537556965, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C6.041150369986185 11.341488511566151, 12.210612183166209 4.244334552127405, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C5.344291267072877 12.143133207841995, 10.816893977339593 5.847623944679093, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C8.414446457345543 14.708336018509971, 16.56260215295586 5.33495512916193, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C6.4214844934095785 17.000976498615042, 12.576678225083935 9.92023608937207, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C6.6772876169141355 22.8037210136902, 13.349741296154498 15.127941102446501, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C6.9544811298598415 22.484846353710854, 13.90412832204591 14.490191782487804, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C6.872640764250068 28.676005271567007, 14.001904414887814 20.474725601124224, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C10.997917141478736 23.93041765614801, 22.25245716934515 10.983550370286228, 31.89026953414718 -0.10348448890603734 M0.13797931854138312 42.520359378862906 C11.256541242895041 29.72991700735603, 22.3751031672487 16.939474635849148, 36.877284942009794 0.25662288638767805 M0.13797931854138312 42.520359378862906 C11.845267458656053 29.05266496824178, 23.552555598770724 15.58497055762065, 36.877284942009794 0.25662288638767805 M1.1886405524609494 47.40872423549325 C16.24604414541426 30.08716284738364, 31.303447738367574 12.76560145927403, 42.520359378862906 -0.13797931854138312 M1.1886405524609494 47.40872423549325 C15.538740655247599 30.900822436788527, 29.88884075803425 14.392920638083801, 42.520359378862906 -0.13797931854138312 M6.831714989314069 47.014122030564195 C15.158556348394061 37.43518679913732, 23.485397707474053 27.85625156771044, 47.50737478672552 0.22212805675232872 M6.831714989314069 47.014122030564195 C20.84115003976956 30.898110545505528, 34.85058509022505 14.78209906044686, 47.50737478672552 0.22212805675232872 M11.818730397176676 47.3742294058579 C21.211286517846283 36.56932958158926, 30.60384263851589 25.76442975732062, 53.15044922357863 -0.1724741481767289 M11.818730397176676 47.3742294058579 C23.229577828526097 34.24755102121452, 34.640425259875514 21.120872636571143, 53.15044922357863 -0.1724741481767289 M17.461804834029795 46.979627200928846 C30.306104344153184 32.20395083159861, 43.150403854276576 17.42827446226838, 58.13746463144125 0.1876332271169865 M17.461804834029795 46.979627200928846 C29.255969708044375 33.41199254030672, 41.05013458205896 19.84435787968459, 58.13746463144125 0.1876332271169865 M22.448820241892403 47.33973457622256 C35.24597035382438 32.6182973849912, 48.04312046575637 17.896860193759842, 63.78053906829436 -0.20696897781207468 M22.448820241892403 47.33973457622256 C32.40388163119093 35.88774646202785, 42.35894302048945 24.435758347833136, 63.78053906829436 -0.20696897781207468 M28.091894678745525 46.9451323712935 C39.423679421275665 33.90940520605776, 50.7554641638058 20.873678040822032, 68.76755447615697 0.1531383974816336 M28.091894678745525 46.9451323712935 C36.86256421475625 36.85563122689101, 45.63323375076697 26.766130082488527, 68.76755447615697 0.1531383974816336 M33.07891008660813 47.30523974658722 C49.00458898942211 28.98484187324387, 64.93026789223609 10.66444399990052, 73.09851085502908 1.2679553529981291 M33.07891008660813 47.30523974658722 C43.409127522921416 35.42168396812881, 53.7393449592347 23.5381281896704, 73.09851085502908 1.2679553529981291 M38.72198452346125 46.91063754165816 C46.490976769857184 37.97343430545929, 54.25996901625312 29.036231069260428, 73.49311305995813 6.911029789851241 M38.72198452346125 46.91063754165816 C48.95423324235933 35.13978188061016, 59.186481961257414 23.36892621956216, 73.49311305995813 6.911029789851241 M43.70899993132386 47.27074491695187 C54.52169625510804 34.8321606691958, 65.33439257889222 22.39357642143973, 73.23165623589668 13.30881380692713 M43.70899993132386 47.27074491695187 C51.29617725229622 38.54269582692153, 58.88335457326858 29.814646736891184, 73.23165623589668 13.30881380692713 M49.35207436817697 46.87614271202281 C58.04537107987899 36.87564882028253, 66.73866779158101 26.87515492854224, 72.97019941183524 19.706597824003016 M49.35207436817697 46.87614271202281 C54.34157254094606 41.13638164618229, 59.33107071371516 35.396620580341775, 72.97019941183524 19.706597824003016 M54.339089776039586 47.23625008731652 C61.493812828987195 39.005682724789736, 68.6485358819348 30.775115362262955, 73.3648016167643 25.34967226085613 M54.339089776039586 47.23625008731652 C59.64835957910307 41.12863384045977, 64.95762938216656 35.02101759360303, 73.3648016167643 25.34967226085613 M59.9821642128927 46.84164788238747 C62.83992437265473 43.554170879182365, 65.69768453241676 40.26669387597726, 73.10334479270284 31.747456277932027 M59.9821642128927 46.84164788238747 C64.76384713880717 41.34095091106735, 69.54553006472162 35.84025393974723, 73.10334479270284 31.747456277932027 M64.96917962075531 47.20175525768118 C67.32639823571641 44.490085434116665, 69.68361685067751 41.77841561055215, 73.49794699763191 37.39053071478514 M64.96917962075531 47.20175525768118 C67.3437430886772 44.47013246324269, 69.71830655659907 41.7385096688042, 73.49794699763191 37.39053071478514 M69.95619502861793 47.561862632974886 C71.15470381114815 46.183135993775196, 72.35321259367839 44.8044093545755, 73.23649017357046 43.78831473186103 M69.95619502861793 47.561862632974886 C70.82261474171672 46.56516076763254, 71.68903445481551 45.5684589022902, 73.23649017357046 43.78831473186103" stroke="#4c6ef5" stroke-width="0.5" fill="none"></path><path d="M0 0 C26.955635350942615 0, 53.91127070188523 0, 72 0 M0 0 C26.84984226822853 0, 53.69968453645706 0, 72 0 M72 0 C72 16.324836088716985, 72 32.64967217743397, 72 46 M72 0 C72 16.064654491841793, 72 32.129308983683586, 72 46 M72 46 C47.6831055700779 46, 23.36621114015579 46, 0 46 M72 46 C47.87400836348533 46, 23.74801672697067 46, 0 46 M0 46 C0 28.00655534118414, 0 10.013110682368279, 0 0 M0 46 C0 30.18186087757349, 0 14.36372175514698, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2423.662496303048 2957.742131981392) rotate(0 25 11.5)"><text x="25" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">never</text></g><g transform="translate(2096.0885167112115 2951.7716658736545) rotate(0 71.39795918367349 18.459183673469397)"><path d="M-1.39677394926548 0.32469500601291656 L144.1485536168425 1.0561283975839615 L143.16979814275192 36.469005918320306 L0.8744791597127914 36.901885843094476" stroke="none" stroke-width="0" fill="#fff"></path><path d="M1.97709359228611 0.2847932428121567 C45.81741551317428 -1.4418476016348118, 94.41446656003902 -1.710245409709763, 144.25420788629935 1.0933693498373032 M0.36778729408979416 -0.539526991546154 C29.279434256453307 -1.328064804577402, 57.55820005426604 -0.7314215951200045, 143.34479577793763 0.8614866212010384 M142.79116085871146 -1.6496993452310562 C142.0197555263934 12.957873272211563, 143.791121168941 28.65417574805262, 143.7805507551043 38.108356779631265 M143.4031320358722 0.810993380844593 C142.26080883488825 14.157132057313394, 143.62355817303828 30.160688031145476, 143.17326481594728 37.808787731643804 M142.3686511884539 36.304374998625406 C109.32375555161619 36.44563753010511, 71.09515935325503 34.99013645054578, 0.7016643434762955 34.95789129119743 M142.0741914059131 36.43621197175611 C86.5527700301488 35.87242209359239, 29.673369833583735 36.724482173166976, 0.9116184040904045 37.65035119485486 M0.7120059877634048 38.15940267425407 C-1.6189305448547313 27.43336544385063, 0.17987040042725105 15.783362759345628, 0.8774517923593521 -0.5245310217142105 M-0.6241615489125252 36.01623979043592 C-0.7518961163610218 25.33034535988554, -0.20926091395318497 13.12852838294845, -0.6112461760640144 0.5358352139592171" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2130.7364758948847 2958.2308495471234) rotate(0 5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(2161.2364758948847 2957.7308495471234) rotate(0 5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(2250.2364758948847 2950.7308495471234) rotate(0 17.75 17.75)"><path d="M1.0561283975839615 0.3738797754049301 L35.05063857138157 0.8744791597127914 L35.48351849615574 35.92132793366909 L1.9206861406564713 36.94069562852383" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-0.055244579911231995 1.2888831049203873 C13.835698738321664 1.590593797005713, 29.412051602452998 -1.8358097254857422, 36.66893516480923 1.669340506196022 M-0.1361897513270378 -0.015486307442188263 C12.416098352149131 0.3740075787529349, 24.77277640923858 0.6458221634849906, 35.12330622226 0.6146547123789787 M34.35250221192837 1.1342719942331314 C35.65061199370771 11.626187809929252, 36.39716779891401 23.263016345351936, 35.518439158797264 33.57663430273533 M34.9268779233098 0.824236087501049 C36.48808241333813 13.18295497186482, 36.6783230349049 25.09360714480281, 35.95243377238512 34.930626802146435 M35.840311869978905 34.69427575170994 C24.49321003295481 36.55228977914899, 13.756322429329153 37.71093874689191, -0.8161541372537613 34.9236406236887 M34.865563578903675 34.619517259299755 C27.62975437156856 36.36826742265374, 20.056245274096728 35.048971777893605, -0.9880843684077263 35.67945259064436 M0.08543048799037933 35.31508578360081 C-2.2144235760346054 24.463641164079306, -0.7448147923126817 12.03542957678437, 0.8267763704061508 1.3221758753061295 M0.1576504185795784 35.44335525482893 C0.021761129833757886 26.45452732257545, 0.8560904965177178 17.933160022646188, 0.16234750300645828 0.6763176247477531" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2251.2364758948847 2951.7308495471234) rotate(0 17.5 4.5)"><path d="M0.3738797754049301 -0.4493614286184311 L35.87447915971279 -0.01648150384426117 L35.42132793366909 10.920686140656471 L1.4406956285238266 8.818684473633766" stroke="none" stroke-width="0" fill="#000"></path><path d="M1.2888831049203873 -0.32364238798618317 C12.456677693873644 1.1030371513217687, 20.028662346303463 1.1786029662936925, 36.66934050619602 0.7355745881795883 M-0.015486307442188263 0.46045345813035965 C9.16053294017911 0.9091530341655016, 18.044003054499626 -0.32902736477553846, 35.61465471237898 -0.0023787543177604675 M35.51042239740491 0.199545132368803 C35.41441536031663 2.4931305393576624, 35.86228826127947 3.923568210750818, 34.1344854362309 9.546492301672696 M35.37090623937547 0.3150808934122324 C35.12133970931173 3.830583215877414, 34.71860935166478 7.0633832830935726, 34.7437820609659 8.903864884749055 M34.19427575170994 7.8848107904195786 C26.276150953024626 7.099078521504998, 18.009286530315876 8.243400439992547, -0.5763593763113022 7.556546077132225 M34.119517259299755 9.21762365847826 C27.099162217229605 9.509931100532413, 16.967410385608673 7.78986288420856, 0.1794525906443596 9.356002993881702 M-0.08321139737963679 8.10263708755374 C0.48412048883736136 5.505495142936707, 0.25264005728065975 2.8551175720989703, 0.5949791438877582 -0.5617453940212727 M-0.025490135326981522 8.865677631273865 C-0.22112558394670487 7.3530406471341845, -0.2603389433026314 5.29688597805798, 0.30434293113648897 0.23762888945639132" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2258.7364758948847 2943.2308495471234) rotate(0 3 7)"><path d="M-0.4493614286184311 0.8744791597127914 L5.983518496155739 0.42132793366909027 L7.920686140656471 15.440695628523827 L-0.18131552636623383 13.718226775527" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-0.09709271639585493 0.4374868556857109 C1.9043979406356812 -0.6291006942093372, 3.503454820811749 0.4621356587111949, 6.2206723764538765 -0.3237161949276924 M0.1381360374391079 0.16466322317719456 C2.354000631719828 0.24713677704334253, 4.0781011573970325 0.18532559216022487, 5.999286373704672 -0.24745490178465843 M6.31040353924036 0.6892426714301108 C6.752667757719754 5.13996829688549, 5.93258256599307 6.161712904274465, 6.850099135935306 15.13539073318243 M6.490125834196806 0.2641425140202045 C6.54305717855692 3.0837545178830625, 6.236466549932957 6.493601659685374, 5.850456487387419 13.785102678090334 M5.665443237125873 14.210499303042889 C3.019250813126564 14.533922265917063, 0.9699410185217858 13.802920459657908, -0.43303617686033247 13.710706774890422 M6.065287097543478 14.273485521227121 C4.492864418774843 13.824867863357067, 2.2501132182776926 14.001006812751294, 0.10680089816451072 14.1861552990973 M-1.395897863805294 14.614216254651547 C-0.3731518493592739 11.442736196517943, 0.572763325124979 9.302724339067936, -0.8738261684775352 -1.2629785791039465 M-0.20894590690732 13.57212767675519 C0.35301359117031095 10.150121044367552, 0.09157219350337978 7.751406190544366, 0.36964493915438656 0.13085792139172558" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(2273.7364758948847 2943.2308495471234) rotate(0 3 7)"><path d="M0.8744791597127914 -0.01648150384426117 L6.42132793366909 1.9206861406564713 L7.440695628523827 13.818684473633766 L-0.2817732244729996 12.524681463837624" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0.4374868556857109 0.32801080495119095 C1.1929924249649049 0.36038982108235357, 4.067655403912068 0.23038164809346198, 5.676283805072307 0.29555464535951614 M0.16466322317719456 0.2584459863603115 C1.9644937478005886 -0.14063534080982207, 3.620968712121248 -0.028340833783149694, 5.752545098215341 -0.09556404724717141 M6.689242671430111 0.8329926028847692 C7.4653328903019425 3.4096589595079427, 4.73304305151105 7.643602232635022, 7.13539073318243 13.246081449091434 M6.264142514020205 0.6232942692935466 C5.753066121041774 3.7143327333033085, 5.716831813752651 6.645714672654868, 5.785102678090334 14.69137409850955 M6.210499303042889 13.411857183277608 C4.6560004323720925 13.72169808253646, 2.022905065119266 13.533508146852256, -0.28929322510957717 13.926730735599994 M6.273485521227121 14.219595154374838 C4.458358680456877 13.716632108986378, 3.2151594825088976 14.119858317673208, 0.18615529909729955 13.702442725747824 M0.6142162546515464 13.632828284800052 C0.26707957848906516 10.318942117691039, 0.938467107862234 4.606571148335933, -1.2629785791039465 -0.8389919266104697 M-0.42787232324481006 14.375084649771452 C-0.48094061791896814 9.69293266609311, 0.48135260164737703 5.528223767131567, 0.13085792139172558 -0.15727650001645088" stroke="#000000" stroke-width="1" fill="none"></path></g><g><g transform="translate(2267.2364758948847 2959.7308495471234) rotate(0 0.8333176635205746 12.12975324690342)"><path d="M1.0933693498373032 -1.9681140035390854 C1.3082746260240674 11.323464896418153, 1.0571361270174384 18.23284052114934, 1.4851821511983871 26.227620497345924 M0.8614866212010384 0.8206919953227043 C-0.10544792670756575 8.520871610604228, 0.41809278134256606 14.990328510887922, 0.181453175842762 25.926251105964184" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(2257.7364758948847 2958.7308495471234) rotate(0 -0.5737110041081905 14.095221109688282)"><path d="M-1.9681140035390854 1.168935164809227 C2.015409979149699 8.67974182162434, -0.5910755698382855 16.876250041462484, 0.22762049734592438 27.969027385115623 M0.8206919953227043 -0.3766937777400017 C0.9413630602508783 9.682583495341241, -0.3251186518371105 19.05568510826677, -0.07374889403581619 28.567135997116566" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(2277.236475894885 2960.2308495471234) rotate(0 0.845221109688282 13.517780814319849)"><path d="M1.168935164809227 1.669340506196022 C1.4343508942052723 8.445026008598507, 2.243330171145499 18.761019625701014, 1.4690273851156235 26.42090691626072 M-0.3766937777400017 0.6146547123789787 C0.7496319456771017 8.212477344460787, 0.9657954874262213 17.513215520046653, 2.0671359971165657 25.721716813743114" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(2286.2364758948847 2968.2308495471234) rotate(0 -16.05447134003043 0.48556103962073394)"><path d="M1.669340506196022 0.7355745881795883 C-13.137781877815724 1.1839011292159558, -24.38983529210091 0.16774636313319208, -33.07909308373928 1.0977548211812973 M0.6146547123789787 -0.0023787543177604675 C-13.95390418469906 -0.44662270858883857, -26.83185791820288 0.43906011268496514, -33.778283186256886 0.49231619387865067" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g><g transform="translate(2285.7364758948847 2977.2308495471234) rotate(0 -17.38605460897088 0.8219596296548843)"><path d="M0.7355745881795883 -1.079053983092308 C-6.266367966607214 0.22969608828425414, -14.539917526319625 1.6245768070220947, -34.9022451788187 2.7229732424020767 M-0.0023787543177604675 -0.8248496726155281 C-14.076804945096374 0.029596001952886586, -26.945613306984306 1.2071309092640878, -35.50768380612135 1.5949947163462639" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(1824.15996631772 1770.2890595675917) rotate(0 244 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"># updating product: initial state</text></g><g transform="translate(1855.6599663177199 2520.2890595675917) rotate(0 275 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"># updating product: updating stock</text></g><g transform="translate(1230.1599663177199 1685.2890595675917) rotate(0 98 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">alternative 1</text></g><g transform="translate(2047.6599663177199 1692.7890595675917) rotate(0 98 21)"><text x="0" y="33" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">alternative 2</text></g><g transform="translate(1410.3187679866014 1348.8928867907737) rotate(0 42.85000000000002 19.5)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.4245540883265806 4.458250329234831, 3.1105650007146095 2.5187166413937736, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.0416068012916408 4.8987807898708216, 2.34467042664473 3.399777562665754, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C3.2858567810230084 8.414078862104724, 6.438568181178406 4.78729927028044, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C2.2853176939057724 9.56506741811414, 4.437490006943934 7.089276382299275, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C4.912805019729161 12.639501354936556, 9.953921482652161 6.840360238868213, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C3.6729466808315223 14.06579521743392, 7.474204804856884 9.69294796386294, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C7.506626709289865 15.75266317612456, 14.746962656844508 7.423609444391108, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C7.989401072722355 15.19729480061559, 15.712511383709488 6.312872693373166, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C7.108748000762871 22.307382619143166, 14.212662063851969 14.13526431335243, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C5.260777704715555 24.433229265198854, 10.516721471757338 18.386957605463806, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C7.808664564618157 27.599233063216616, 15.873952015623992 18.321181184423438, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C7.298340080009983 28.1862942277412, 14.853303046407644 19.49530351347261, 31.89026953414718 -0.10348448890603734 M2.1061564055129054 40.256230638194594 C9.780493364357602 31.427915854371093, 17.454830323202298 22.599601070547592, 36.877284942009794 0.25662288638767805 M2.1061564055129054 40.256230638194594 C13.368263852888148 27.300658032005664, 24.63037130026339 14.345085425816738, 36.877284942009794 0.25662288638767805 M7.093171813375516 40.6163380134883 C14.974944290744936 31.549395962618448, 22.85671676811436 22.482453911748596, 42.520359378862906 -0.13797931854138312 M7.093171813375516 40.6163380134883 C19.465076460800553 26.384089769939752, 31.836981108225594 12.151841526391202, 42.520359378862906 -0.13797931854138312 M12.736246250228632 40.221735808559245 C24.22926903898746 27.000525488899985, 35.72229182774629 13.779315169240725, 47.50737478672552 0.22212805675232872 M12.736246250228632 40.221735808559245 C23.12470329438591 28.27118302518816, 33.51316033854319 16.320630241817078, 47.50737478672552 0.22212805675232872 M17.723261658091243 40.58184318385296 C31.052683527570583 25.24809737868312, 44.382105397049926 9.914351573513276, 53.15044922357863 -0.1724741481767289 M17.723261658091243 40.58184318385296 C29.795719308109998 26.694069305757793, 41.86817695812876 12.806295427662622, 53.15044922357863 -0.1724741481767289 M22.710277065953854 40.941950559146676 C32.38282151190626 29.81496101108199, 42.055365957858655 18.687971463017305, 58.13746463144125 0.1876332271169865 M22.710277065953854 40.941950559146676 C33.30055899329363 28.75922480637138, 43.890840920633394 16.576499053596084, 58.13746463144125 0.1876332271169865 M28.353351502806966 40.54734835421761 C40.44468713249262 26.63785784472148, 52.53602276217828 12.728367335225354, 63.78053906829436 -0.20696897781207468 M28.353351502806966 40.54734835421761 C39.953269725938405 27.203168903979936, 51.55318794906984 13.858989453742264, 63.78053906829436 -0.20696897781207468 M33.34036691066958 40.90745572951133 C41.61400376214182 31.389725282758157, 49.88764061361407 21.871994836004983, 68.76755447615697 0.1531383974816336 M33.34036691066958 40.90745572951133 C47.01201809050106 25.18002013768735, 60.68366927033254 9.452584545863374, 68.76755447615697 0.1531383974816336 M38.98344134752269 40.51285352458227 C48.167500219764634 29.947802347897323, 57.35155909200658 19.38275117121238, 74.41062891301009 -0.2414638074474169 M38.98344134752269 40.51285352458227 C50.12455077371315 27.696473219300575, 61.26566019990361 14.880092914018881, 74.41062891301009 -0.2414638074474169 M43.97045675538531 40.872960899875984 C54.950211905547526 28.242197456107192, 65.92996705570975 15.6114340123384, 79.3976443208727 0.11864356784629138 M43.97045675538531 40.872960899875984 C54.90763642626359 28.291174942397724, 65.84481609714189 15.70938898491946, 79.3976443208727 0.11864356784629138 M49.613531192238426 40.47835869494692 C63.22322650475755 24.82219517552106, 76.83292181727667 9.166031656095196, 85.04071875772581 -0.27595863708276624 M49.613531192238426 40.47835869494692 C63.59626442284176 24.393064139861472, 77.5789976534451 8.307769584776025, 85.04071875772581 -0.27595863708276624 M54.60054660010103 40.838466070240635 C65.05761358779769 28.80898657540063, 75.51468057549434 16.779507080560627, 88.0595570786169 2.348277478879261 M54.60054660010103 40.838466070240635 C64.76865042983721 29.141400663169186, 74.93675425957338 17.444335256097734, 88.0595570786169 2.348277478879261 M60.24362103695415 40.44386386531157 C68.21785733748133 31.27055435347016, 76.19209363800852 22.097244841628747, 88.45415928354596 7.991351915732373 M60.24362103695415 40.44386386531157 C70.07031189293934 29.139549157058624, 79.89700274892454 17.83523444880568, 88.45415928354596 7.991351915732373 M65.23063644481675 40.80397124060529 C73.59383619649051 31.183210463001203, 81.95703594816428 21.562449685397112, 88.19270245948451 14.389135932808273 M65.23063644481675 40.80397124060529 C72.01490616069215 32.99956169339599, 78.79917587656755 25.19515214618668, 88.19270245948451 14.389135932808273 M70.87371088166988 40.40936903567623 C74.86289472535546 35.82033797130387, 78.85207856904103 31.231306906931508, 87.93124563542307 20.786919949884158 M70.87371088166988 40.40936903567623 C75.0218753433517 35.637451691000514, 79.17003980503353 30.865534346324804, 87.93124563542307 20.786919949884158 M75.8607262895325 40.76947641096994 C79.60436868969872 36.46290846588569, 83.34801108986494 32.156340520801436, 88.32584784035213 26.429994386737274 M75.8607262895325 40.76947641096994 C79.53695074376839 36.54046394096367, 83.21317519800428 32.3114514709574, 88.32584784035213 26.429994386737274 M81.5038007263856 40.374874206040886 C83.00849972587095 38.64391601465589, 84.51319872535629 36.9129578232709, 88.06439101629068 32.82777840381317 M81.5038007263856 40.374874206040886 C83.04239395530837 38.60492516392397, 84.58098718423113 36.83497612180707, 88.06439101629068 32.82777840381317" stroke="#fa5252" stroke-width="0.5" fill="none"></path><path d="M0 0 C32.74580490000551 0, 65.49160980001102 0, 85.70000000000013 0 M0 0 C19.455593113824758 0, 38.911186227649516 0, 85.70000000000013 0 M85.70000000000013 0 C85.70000000000013 13.62363718673587, 85.70000000000013 27.24727437347174, 85.70000000000013 39 M85.70000000000013 0 C85.70000000000013 7.82143609598279, 85.70000000000013 15.64287219196558, 85.70000000000013 39 M85.70000000000013 39 C56.40713170640179 39, 27.114263412803453 39, 0 39 M85.70000000000013 39 C63.53586610801528 39, 41.37173221603042 39, 0 39 M0 39 C0 25.79555174186826, 0 12.591103483736518, 0 0 M0 39 C0 26.93629071637988, 0 14.872581432759759, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1425.6641836672989 840.473507170834) rotate(0 21.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">clear</text></g><g transform="translate(1406.5687679866014 833.2238730819438) rotate(0 42.85000000000002 19.5)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.4555318372155774 4.422614505586104, 3.172520498492603 2.447444994096318, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C1.1870386413074132 4.7314805957126564, 2.6355341066762747 3.0651771743494245, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C2.762329949078644 9.016327589906023, 5.391514517289677 5.991796725883039, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C2.8222380466076165 8.947411207171978, 5.511330712347622 5.853963960414949, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C6.064106454627717 11.315080557041043, 12.256524352449272 4.1915186430771865, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C3.24002755519765 14.56381170244487, 6.608366553589139 10.68898093388484, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C7.425263986294751 15.846260282183612, 14.58423721085428 7.610803656509212, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C5.943864090256802 17.55041592104616, 11.621437418778381 11.019114934234302, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C7.471353066344916 21.89025320739928, 14.937872195016059 13.301005489864657, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C5.357450122959003 24.322020369401937, 10.710066308244233 18.164539813869972, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C9.23323120088127 25.960456610878424, 18.72308528815022 15.043628279747054, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C11.791742976225766 23.01722549501918, 23.84010883883921 9.157166048028564, 31.89026953414718 -0.10348448890603734 M2.1061564055129054 40.256230638194594 C16.01034648426053 24.261289643607526, 29.914536563008152 8.266348649020458, 36.877284942009794 0.25662288638767805 M2.1061564055129054 40.256230638194594 C10.806458292634769 30.24767821396427, 19.506760179756633 20.23912578973395, 36.877284942009794 0.25662288638767805 M7.093171813375516 40.6163380134883 C16.157048766897635 30.189540319217848, 25.220925720419753 19.76274262494739, 42.520359378862906 -0.13797931854138312 M7.093171813375516 40.6163380134883 C18.769447291424736 27.18431958953109, 30.445722769473957 13.752301165573876, 42.520359378862906 -0.13797931854138312 M12.736246250228632 40.221735808559245 C20.590166252526892 31.18683436507417, 28.44408625482515 22.15193292158909, 47.50737478672552 0.22212805675232872 M12.736246250228632 40.221735808559245 C22.099060073144468 29.451050583984703, 31.461873896060304 18.680365359410164, 47.50737478672552 0.22212805675232872 M17.723261658091243 40.58184318385296 C26.69354294820576 30.2627149838195, 35.663824238320274 19.943586783786042, 53.15044922357863 -0.1724741481767289 M17.723261658091243 40.58184318385296 C25.080546201339722 32.118255482364454, 32.4378307445882 23.65466778087595, 53.15044922357863 -0.1724741481767289 M22.710277065953854 40.941950559146676 C34.63283553007527 27.226615968775953, 46.55539399419669 13.51128137840523, 58.13746463144125 0.1876332271169865 M22.710277065953854 40.941950559146676 C32.99233191221806 29.11379950269066, 43.274386758482265 17.285648446234642, 58.13746463144125 0.1876332271169865 M28.353351502806966 40.54734835421761 C35.61771520518492 32.19065385243897, 42.88207890756287 23.833959350660326, 63.78053906829436 -0.20696897781207468 M28.353351502806966 40.54734835421761 C42.3260917323811 24.47354943180949, 56.29883196195524 8.399750509401372, 63.78053906829436 -0.20696897781207468 M33.34036691066958 40.90745572951133 C47.27698140814668 24.87521470799536, 61.213595905623784 8.842973686479397, 68.76755447615697 0.1531383974816336 M33.34036691066958 40.90745572951133 C42.363685514622375 30.527315079234448, 51.38700411857516 20.14717442895757, 68.76755447615697 0.1531383974816336 M38.98344134752269 40.51285352458227 C50.201826110359974 27.607578113364703, 61.42021087319726 14.702302702147133, 74.41062891301009 -0.2414638074474169 M38.98344134752269 40.51285352458227 C52.71637700351996 24.714918207524086, 66.44931265951723 8.9169828904659, 74.41062891301009 -0.2414638074474169 M43.97045675538531 40.872960899875984 C56.20877578647401 26.794385329019903, 68.44709481756271 12.715809758163818, 79.3976443208727 0.11864356784629138 M43.97045675538531 40.872960899875984 C51.65038491822366 32.038214171619856, 59.330313081062 23.20346744336373, 79.3976443208727 0.11864356784629138 M49.613531192238426 40.47835869494692 C59.5617026089435 29.03429658755033, 69.50987402564857 17.59023448015374, 85.04071875772581 -0.27595863708276624 M49.613531192238426 40.47835869494692 C63.703566274137145 24.269627480094943, 77.79360135603586 8.060896265242967, 85.04071875772581 -0.27595863708276624 M54.60054660010103 40.838466070240635 C62.270941628361385 32.01468595882482, 69.94133665662174 23.190905847409006, 88.0595570786169 2.348277478879261 M54.60054660010103 40.838466070240635 C66.07942668606204 27.633525069072714, 77.55830677202303 14.428584067904794, 88.0595570786169 2.348277478879261 M60.24362103695415 40.44386386531157 C68.07941910245168 31.42980932539971, 75.91521716794921 22.41575478548785, 88.45415928354596 7.991351915732373 M60.24362103695415 40.44386386531157 C70.04673423488033 29.16667215000598, 79.8498474328065 17.889480434700385, 88.45415928354596 7.991351915732373 M65.23063644481675 40.80397124060529 C73.69913319971204 31.062080117120125, 82.1676299546073 21.320188993634957, 88.19270245948451 14.389135932808273 M65.23063644481675 40.80397124060529 C72.41038734454995 32.54461263383561, 79.59013824428314 24.28525402706593, 88.19270245948451 14.389135932808273 M70.87371088166988 40.40936903567623 C77.2753954624955 33.04507334090056, 83.67708004332113 25.680777646124895, 87.93124563542307 20.786919949884158 M70.87371088166988 40.40936903567623 C75.51899407856129 35.06558200337773, 80.16427727545272 29.721794971079234, 87.93124563542307 20.786919949884158 M75.8607262895325 40.76947641096994 C80.54315134759022 35.38296255500032, 85.22557640564797 29.996448699030687, 88.32584784035213 26.429994386737274 M75.8607262895325 40.76947641096994 C79.81466061450901 36.22099527929023, 83.76859493948552 31.67251414761051, 88.32584784035213 26.429994386737274 M81.5038007263856 40.374874206040886 C83.66022725489519 37.89418925515019, 85.81665378340477 35.41350430425949, 88.06439101629068 32.82777840381317 M81.5038007263856 40.374874206040886 C83.60362085695817 37.95930746698352, 85.70344098753074 35.54374072792615, 88.06439101629068 32.82777840381317" stroke="#fa5252" stroke-width="0.5" fill="none"></path><path d="M0 0 C21.05272591106597 0, 42.10545182213194 0, 85.70000000000013 0 M0 0 C20.390299159362943 0, 40.780598318725886 0, 85.70000000000013 0 M85.70000000000013 0 C85.70000000000013 12.150230193883182, 85.70000000000013 24.300460387766364, 85.70000000000013 39 M85.70000000000013 0 C85.70000000000013 11.797666608542205, 85.70000000000013 23.59533321708441, 85.70000000000013 39 M85.70000000000013 39 C57.69139444358655 39, 29.682788887172975 39, 0 39 M85.70000000000013 39 C66.92966488234708 39, 48.15932976469404 39, 0 39 M0 39 C0 24.39182279035449, 0 9.783645580708978, 0 0 M0 39 C0 27.356765545159575, 0 15.713531090319155, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(1415.6641836672989 260.31505805746497) rotate(0 21.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">clear</text></g><g transform="translate(1396.5687679866014 253.0654239685748) rotate(0 42.85000000000002 19.5)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.2614568240614483 6.397784017075889 C1.5247266891293827 4.343014934002126, 3.3109102023202137 2.2882458509283623, 4.98701540786261 0.36010737529371317 M-0.2614568240614483 6.397784017075889 C0.880941370554186 5.083605225523745, 2.0233395651698203 3.769426433971601, 4.98701540786261 0.36010737529371317 M0.13314538086761107 12.040858453929006 C4.035985275130465 7.551154741127234, 7.938825169393319 3.061451028325461, 10.630089844715727 -0.03449482963534578 M0.13314538086761107 12.040858453929006 C2.67071835281382 9.121714675984162, 5.208291324760029 6.202570898039318, 10.630089844715727 -0.03449482963534578 M-0.12831144319383903 18.438642471004897 C5.889131394208884 11.516366338598454, 11.906574231611607 4.594090206192011, 15.617105252578337 0.32561254565836695 M-0.12831144319383903 18.438642471004897 C5.443982487779084 12.028451577064278, 11.016276418752007 5.618260683123658, 15.617105252578337 0.32561254565836695 M0.26629076173522215 24.081716907858013 C6.002808864492601 17.48260771499452, 11.73932696724998 10.883498522131026, 21.260179689431453 -0.06898965927069156 M0.26629076173522215 24.081716907858013 C7.539391620207313 15.714971457739715, 14.812492478679404 7.348226007621417, 21.260179689431453 -0.06898965927069156 M0.004833937673772937 30.4795009249339 C9.906993859538126 19.08836898757109, 19.80915378140248 7.69723705020828, 26.247195097294064 0.29111771602302206 M0.004833937673772937 30.4795009249339 C6.400185529507074 23.12249050061828, 12.795537121340375 15.765480076302657, 26.247195097294064 0.29111771602302206 M-0.25662288638767805 36.877284942009794 C10.422681947823541 24.592150049650606, 21.10198678203476 12.307015157291417, 31.89026953414718 -0.10348448890603734 M-0.25662288638767805 36.877284942009794 C7.042802353155541 28.480256755567623, 14.34222759269876 20.083228569125453, 31.89026953414718 -0.10348448890603734 M2.1061564055129054 40.256230638194594 C14.487790658574035 26.01278976370757, 26.869424911635164 11.769348889220545, 36.877284942009794 0.25662288638767805 M2.1061564055129054 40.256230638194594 C14.621202188054145 25.859317355034616, 27.136247970595385 11.462404071874637, 36.877284942009794 0.25662288638767805 M7.093171813375516 40.6163380134883 C18.525508948093822 27.464938553008803, 29.95784608281213 14.313539092529304, 42.520359378862906 -0.13797931854138312 M7.093171813375516 40.6163380134883 C18.172062686112294 27.87153196644271, 29.250953558849073 15.12672591939712, 42.520359378862906 -0.13797931854138312 M12.736246250228632 40.221735808559245 C20.949472545463763 30.773499757163894, 29.162698840698894 21.325263705768542, 47.50737478672552 0.22212805675232872 M12.736246250228632 40.221735808559245 C22.747549333443413 28.705049026514676, 32.75885241665819 17.188362244470106, 47.50737478672552 0.22212805675232872 M17.723261658091243 40.58184318385296 C28.57316026875329 28.100462600596217, 39.423058879415336 15.619082017339469, 53.15044922357863 -0.1724741481767289 M17.723261658091243 40.58184318385296 C29.94616841392979 26.52099740752805, 42.16907516976834 12.46015163120314, 53.15044922357863 -0.1724741481767289 M22.710277065953854 40.941950559146676 C30.60928203926329 31.855184789369865, 38.50828701257272 22.768419019593058, 58.13746463144125 0.1876332271169865 M22.710277065953854 40.941950559146676 C34.24309550344289 27.674960582443322, 45.77591394093193 14.407970605739969, 58.13746463144125 0.1876332271169865 M28.353351502806966 40.54734835421761 C36.5691095068009 31.09619990504985, 44.784867510794825 21.645051455882093, 63.78053906829436 -0.20696897781207468 M28.353351502806966 40.54734835421761 C41.74632990408641 25.140489122792403, 55.139308305365844 9.73362989136719, 63.78053906829436 -0.20696897781207468 M33.34036691066958 40.90745572951133 C40.74931779527038 32.384432701214415, 48.158268679871185 23.8614096729175, 68.76755447615697 0.1531383974816336 M33.34036691066958 40.90745572951133 C43.37070339550055 29.368873523565544, 53.401039880331524 17.83029131761976, 68.76755447615697 0.1531383974816336 M38.98344134752269 40.51285352458227 C50.89271684618298 26.81279923803224, 62.80199234484327 13.112744951482213, 74.41062891301009 -0.2414638074474169 M38.98344134752269 40.51285352458227 C52.38933444687543 25.09113763250474, 65.79522754622818 9.669421740427207, 74.41062891301009 -0.2414638074474169 M43.97045675538531 40.872960899875984 C57.25506820175456 25.59076358976619, 70.53967964812381 10.3085662796564, 79.3976443208727 0.11864356784629138 M43.97045675538531 40.872960899875984 C54.01549183903063 29.317469890223748, 64.06052692267596 17.761978880571508, 79.3976443208727 0.11864356784629138 M49.613531192238426 40.47835869494692 C61.766908843533585 26.49749700387109, 73.92028649482874 12.516635312795263, 85.04071875772581 -0.27595863708276624 M49.613531192238426 40.47835869494692 C57.59209042061002 31.300076223486606, 65.5706496489816 22.12179375202629, 85.04071875772581 -0.27595863708276624 M54.60054660010103 40.838466070240635 C67.59245085286398 25.892989868221868, 80.58435510562691 10.947513666203104, 88.0595570786169 2.348277478879261 M54.60054660010103 40.838466070240635 C66.71712723226744 26.899934507450432, 78.83370786443385 12.961402944660232, 88.0595570786169 2.348277478879261 M60.24362103695415 40.44386386531157 C67.69401400131045 31.873167177734402, 75.14440696566675 23.302470490157237, 88.45415928354596 7.991351915732373 M60.24362103695415 40.44386386531157 C68.99039340992344 30.381853262294154, 77.73716578289273 20.319842659276738, 88.45415928354596 7.991351915732373 M65.23063644481675 40.80397124060529 C69.92256920361453 35.40652002607902, 74.6145019624123 30.009068811552748, 88.19270245948451 14.389135932808273 M65.23063644481675 40.80397124060529 C71.3558200342678 33.75775355087222, 77.48100362371885 26.71153586113916, 88.19270245948451 14.389135932808273 M70.87371088166988 40.40936903567623 C77.66819664726737 32.59320726762002, 84.46268241286487 24.77704549956382, 87.93124563542307 20.786919949884158 M70.87371088166988 40.40936903567623 C76.62275497634309 33.79585033744366, 82.3717990710163 27.182331639211093, 87.93124563542307 20.786919949884158 M75.8607262895325 40.76947641096994 C79.17495020512054 36.95689792402115, 82.48917412070857 33.144319437072355, 88.32584784035213 26.429994386737274 M75.8607262895325 40.76947641096994 C79.07364264013388 37.07343894619429, 82.28655899073526 33.37740148141864, 88.32584784035213 26.429994386737274 M81.5038007263856 40.374874206040886 C83.683618584539 37.86728060852505, 85.8634364426924 35.35968701100921, 88.06439101629068 32.82777840381317 M81.5038007263856 40.374874206040886 C83.62134083128937 37.938922968336136, 85.73888093619314 35.50297173063139, 88.06439101629068 32.82777840381317" stroke="#fa5252" stroke-width="0.5" fill="none"></path><path d="M0 0 C32.98184273473924 0, 65.96368546947848 0, 85.70000000000013 0 M0 0 C32.54269795306032 0, 65.08539590612064 0, 85.70000000000013 0 M85.70000000000013 0 C85.70000000000013 9.08658194616437, 85.70000000000013 18.17316389232874, 85.70000000000013 39 M85.70000000000013 0 C85.70000000000013 10.802469717711212, 85.70000000000013 21.604939435422423, 85.70000000000013 39 M85.70000000000013 39 C52.886900880411346 39, 20.073801760822562 39, 0 39 M85.70000000000013 39 C68.02522339455794 39, 50.35044678911574 39, 0 39 M0 39 C0 26.94815444871783, 0 14.896308897435663, 0 0 M0 39 C0 28.28894211128354, 0 17.57788422256708, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g></svg> \ No newline at end of file
diff --git a/backoffice-product-create.svg b/images/backoffice-product-create.svg
index 64bed16f..64bed16f 100644
--- a/backoffice-product-create.svg
+++ b/images/backoffice-product-create.svg
diff --git a/backoffice-product-create.with-stock.svg b/images/backoffice-product-create.with-stock.svg
index 4027af8e..4027af8e 100644
--- a/backoffice-product-create.with-stock.svg
+++ b/images/backoffice-product-create.with-stock.svg
diff --git a/backoffice-product-create.without-stock.svg b/images/backoffice-product-create.without-stock.svg
index 04aabeb4..04aabeb4 100644
--- a/backoffice-product-create.without-stock.svg
+++ b/images/backoffice-product-create.without-stock.svg
diff --git a/backoffice-product-list.actions.svg b/images/backoffice-product-list.actions.svg
index b97af851..b97af851 100644
--- a/backoffice-product-list.actions.svg
+++ b/images/backoffice-product-list.actions.svg
diff --git a/backoffice-product-list.svg b/images/backoffice-product-list.svg
index d4db4251..d4db4251 100644
--- a/backoffice-product-list.svg
+++ b/images/backoffice-product-list.svg
diff --git a/backoffice-product-update.svg b/images/backoffice-product-update.svg
index df3529c0..df3529c0 100644
--- a/backoffice-product-update.svg
+++ b/images/backoffice-product-update.svg
diff --git a/backoffice-reserve-create.svg b/images/backoffice-reserve-create.svg
index b2dcd3a4..b2dcd3a4 100644
--- a/backoffice-reserve-create.svg
+++ b/images/backoffice-reserve-create.svg
diff --git a/backoffice-reserve-details.svg b/images/backoffice-reserve-details.svg
index f86d00bd..f86d00bd 100644
--- a/backoffice-reserve-details.svg
+++ b/images/backoffice-reserve-details.svg
diff --git a/backoffice-reserve-details.unfunded.svg b/images/backoffice-reserve-details.unfunded.svg
index 529c520e..529c520e 100644
--- a/backoffice-reserve-details.unfunded.svg
+++ b/images/backoffice-reserve-details.unfunded.svg
diff --git a/backoffice-reserve-list.svg b/images/backoffice-reserve-list.svg
index c9380e36..c9380e36 100644
--- a/backoffice-reserve-list.svg
+++ b/images/backoffice-reserve-list.svg
diff --git a/images/backoffice-reward-create.confirmation.svg b/images/backoffice-reward-create.confirmation.svg
new file mode 100644
index 00000000..90200c1b
--- /dev/null
+++ b/images/backoffice-reward-create.confirmation.svg
@@ -0,0 +1,16 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 571.8889058430991 551.2222391764319" width="571.8889058430991" height="551.2222391764319">
+ <!-- svg-source:excalidraw -->
+ <!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO2caVPiSlx1MDAxN8ffz6ewmLdjpvflvtNRwd1cdTAwMTFwmaduWVx1MDAxMVx1MDAwMkRcdTAwMDKBXHUwMDEw1lv3u99cdTAwMTNQiFmYaIlm5pmURUlcdTAwMTbS6f6d0/9zujv/fNraKvjTnlX4a6tgTWqmY9c9c1xc+Fx1MDAxMuxcdTAwMWZZ3sB2u3CIzL9cdTAwMGbcoVebn9ny/d7gr69fV1dcdTAwMTg1t7O4ynKsjtX1XHUwMDA3cN7/4PvW1j/zz9B9PKvmm92mY80vmFx1MDAxZlrdikpcdTAwMTXde+Z257fFhEosuF5cdTAwMWW3XHUwMDA3e3A336rDwYbpXGas1ZFgV1x1MDAwMZ1Zlmz1XHUwMDFi7nfbLlx1MDAxZVxcNe4n4q60umnDdpyyP3VcdTAwMTaPZNZaQy9UpIHvuW3r2q77reDekf3L61x1MDAwNi5UwOoqz1x1MDAxZDZbXWtcdTAwMTA8PlrudXtmzfanwe+g1d5FXHUwMDFkhM+bXHUwMDA0Z1AuXHJJXHUwMDE1YlghqjlcdTAwMTLLw/NcdTAwMWaghFx1MDAxYZgoojAhRGpcIlwiJfvmOq5cdTAwMTeU7DOab6uy3Zu1dlx1MDAxM1xu2K0vz/E9szvomVx1MDAxZTTY6rzx4zNzjlxypZRGXFwxirRe1UHLspstPziFYlx1MDAwM4pBqMZSMEpWZbHmrYIx4lx1MDAwNLHQpUFcdTAwMDF6h/U5XHUwMDFlf0crtWV6vcfKK1xmgi+hwlx1MDAwN+XeX7D1dPn82L9fkinzrYmfXHUwMDA0XHUwMDE4XHUwMDExMlx1MDAxNTCNlZaM8cyEeUWvR0o7u/rq9vL2cHy+U1H45P1cYsOvI4xRQEhcdTAwMTEmNNFAXHUwMDE5U1x1MDAxMcJcdTAwMDQ2hKKKU0lcdOeKbIwwolicqThFXFxxIIxcdTAwMTG9XHUwMDExilat5Xb9sj2z5lx1MDAwNXu298Ds2M70yVx1MDAxMS4wXHUwMDBi8IJcdTAwMWJU7N5WzbNMYGRrMKzVrEFj6MC5oTpcdTAwMTlYjt2d/6p4dvmOYzdcdTAwMDNcIlx1MDAwYo7VeI6qb4NfXVx1MDAxZfbdXuF1qCuRhrpWjGsqJc6M+rjpXFzYfZ9dXHUwMDFl3lx1MDAxZbRcdTAwMGXrvZm135/m3pkyTFxyQThcdTAwMTWCSs4jrpRxZVx1MDAxMCZcdTAwMTEhXFxcdTAwMTJF2eZcXGnI5yw5JzTKOUFcdTAwMWFKglno7I2DjrKCbnbgJ/1ErrHaXGbXa4VcdTAwMDLDPFxybvBgnFwigTjNTHfrUlxmeqd6rK1W0S19R6VcdTAwMDfbOsg93Vx1MDAwMnODSFx1MDAxNbhpRjWKSlx1MDAwNca5IYApXGamzlx1MDAxMZGb41x1MDAxYsOddGiTSbwrg1wixiRdfPK4WGCgIbAgXHUwMDFi8vOvc6FcdTAwMWOnUcZcdTAwMDVoMKR0dlx1MDAxN3qKO/bxpL93Tu5cdTAwMDfDSu1cdTAwMWWXr/3b3EPGMEt3oVx1MDAxY4NYXHUwMDE1XHUwMDA0KeidXHRccnXnb02Y1lx0RMU8KFx1MDAxNppcdTAwMDNcXCBLc+hBXHUwMDFmhlx1MDAwM99ugFx1MDAwYvRcdTAwMDO23tORptFNaXqwJSW0NyFcIjveP5o/XHUwMDBlXHUwMDFhvDhzurWWdz6rltDo+iz/eFx1MDAxM2wwRDGRXHUwMDE4Qlx1MDAxY1wiI2JYQFx1MDAxMEQhuCFEgV6iXHUwMDFi4zubQqCg2lx1MDAxOFx1MDAxNSSPePughKuXJ/lRXGJU6jS6obNUREuaPZcwLlx1MDAxZdjbpdnp7YNse768d1x1MDAwZbyZnXu4OWdcdTAwMDZcdTAwMTZAL8R8gLYmz+GeXHUwMDBiXHUwMDA0plx1MDAxNUKgXHUwMDBmXHUwMDA03lxcoFx1MDAwN1x1MDAxMSVcbm9cdKlcdTAwMDSQXHUwMDA3WLPlJjWPwk8wXHUwMDE2XHUwMDEwtTK6XHUwMDEx+F/lQEGtrImwXHUwMDE05So7YXtcdTAwMTd2iVx1MDAxNFH1x953VpuUr0tH/aNK/lx0XHUwMDEzyIDQiSiFtFx1MDAwNp5UlLD3XG6xXHUwMDE4SWAq7kC1QEgp8Y6phMxcdTAwMGW0Wt57kfOswZ0tb4377Nj1OrTZ6z0olql4Y07AjCGyyJ4sq7W3jyfV6ezo29GBPz3lpGmeXHUwMDFk51x1MDAxZvD1LpSDfEBcdTAwMWNcdTAwMGJcYjeZXGLX15vnyoQ2wP1xIHj+maBcdTAwMTcwXCLzbOzThmVcdTAwMTR/XHLBoGCCf0A+di1oJFx1MDAxNKrHQOMgU5lcYoWUP1x1MDAwM80x7YtSu7G7PzlcdTAwMTdcdTAwMGanxSn2On7+hSg8J5BcdTAwMDRtgyg0UkyHMmlgiTjDXHUwMDFhfKlmm1OicFx1MDAxN0MyXHUwMDA08lx1MDAxZtw15Ywk5WhRlCwswctTXHUwMDE2lshcdTAwMWJHa9Hak9Ld8FCcXFxbvb5f5Xd7hzM9latfS+7CXHUwMDFmpT8zXHUwMDE4lloqpjFGOFLlXHUwMDEyYltccj08J1xmOrdw1/ZUVYrGqybU58RcdTAwMWL6rdrqo1x1MDAxMX5t0y4zPYpiXG5cdTAwMTI8Nlx1MDAxNFx1MDAxM3Tk6a5cdTAwMDC8r1Ba6SyiKk5Rd+g4sU53XHUwMDE0XGZgblxyu77thKr3pd33S1x1MDAwMprkLv71vlx1MDAxM3qD1Fxuo4C3XHUwMDAyZZ9dhZ5Nv1x1MDAwZrarcvvHxJveN8r9fmfUT8tRRVx1MDAwMPqw8axAg4L0hFx1MDAwZVpjJXUolF7YMeJcdTAwMDZHXHUwMDFjJKrgQrNQz/lcbnP83Gg0XHUwMDEyfCYjXHUwMDA2RCxweyokuM2kbFx1MDAxNVx1MDAxNcbqOFWSRa2CaKbA64aaM2xmj/tgL25+r9dvxHW1zLtcdTAwMGaNabvS3r9cdTAwMWEty1x1MDAxNGBz5l7soHJtdNhxy9eNi1J/xzkrPFx1MDAxZf+YOImlJpq04oyCfMqOqLlz0FLn++rWrXWt89NSV15eXeZcdTAwMWRRzVxy6Njnf1x1MDAxMFx1MDAwZkU7XHUwMDFhbGhcdTAwMDExL1x0cuMhY31ccp/PTljyieI8kliAzThccrRhSvL0nfh6iVx1MDAxM15cdTAwMTX0yZ1/zUVeXHUwMDE1q/S4XHRkuYBAOFNcdTAwMWa24N3at/Slq8ZHXHUwMDFlaez22/1L1u6kydm88Fx1MDAwZarJXHUwMDEw63hnOeCdXHUwMDA0PaNWSP3M4/5cdTAwMDE+U7YgPVx1MDAxOYa1okFts+zUXHUwMDBmadPbtlx1MDAxZfjukdxunl/ss+Jeg+ecelx1MDAxOVxmlaVSj9jbUa+EsrSIg09B6iRIj/Dep1RcdTAwMDDIaK6VSo7X8iAmflx1MDAwMlx1MDAxYkqDTUFIx6Wi2TNT11x1MDAwZo32bGBcdTAwMWWc7N5cdTAwMTCNrVG9WJ2kpV7zw9o6XHUwMDBmXHUwMDBiknezXHUwMDFlliZgpqOMcSapXHUwMDA0MZw8nyX/jKWHoopcdTAwMDbJz+wpqdnk4Hr7crtyV1x1MDAxMsP2pKNbN7r+kHfCgpmmaYRcdC3eTrOmeTNcdTAwMTFnXGbHwiasXHUwMDE5lVxiqZRxofxTlu7JMJFcdTAwMTRrjF5cdTAwMTC/d9BcZlx1MDAxZJ82pj92K5ei3S6OXFx2dJV30Kj6XHUwMDE1QFOEKIwpzS9nc/WXhFx1MDAxOE2dXGKKOVx1MDAxNlwiXHUwMDE4U8jeW9rjc1x1MDAwYlW/nfW7h2TW7Lf65cZVK/eI4XXxXGLdvDJDScKMiLgwI9CvKM4+VpiFLjc9f9fu1u1us1x1MDAxMMmhWt16ypGea4eXgFx1MDAwNNvqv61V48y/LP//+0vy2as6XG62oM5Wl8Se1zFcdTAwMDf+N7fTsX0g+FwiKEe0cPNH2vE8d9yyzHrCQ0WPvdLm1kRDWlxiySh+wdgpL5ZbZ2jv5NC52b3qifaP5s113m2OkHU5L/JRNqeiXHUwMDE2p1x1MDAxNKdcXFwi/cfink6IWJz6XHUwMDE17C1dRlx1MDAxMU5cYqfsXHUwMDA1I8ju/o58uO/vnlfGO4O94Z3VnnXynmKW7Cdd3MZVXHUwMDE0TjS3hNxcdTAwMDP0cJTnI+mWXHUwMDAza8NcdTAwMTFr479I/5Y6pEM0XHUwMDBmIEPZ7e20OFx1MDAxMros++OLITk9UfSoU2nmPtnH0Vx1MDAxYXsjbzikk5rsS5iZXHUwMDExn5iBOSX02UTu/3N7217VW+T8/Fx1MDAxYVx1MDAxYkvPXHUwMDExSMm5XHUwMDA0rZV9ov7wou669Vx1MDAxMml5buWkV7o5b5lnaYud8mRt6WKSonewtqQkQdTawCGA0CDyT+f2uG2vqi3YcFx1MDAwZYxtYVx1MDAwNPzoxGp3Kt3R6LCIm/XxpEGPL+LTxlx1MDAxMlJ3i1x1MDAwMU6lIH7hXFxTjbiQobdcdTAwMTIsiFTEQMAsoVxuXHUwMDAzkCHnu1x1MDAxNEtUXHUwMDE4XCK08YT5y1RcdTAwMWFSSlx1MDAxNcx7XHUwMDE3WMvQmPGbTC37rEhNYyvF8n/BaWWYIIEwZ7E1e4V5LjXNhVxuoYJcdFx1MDAxYVwiy3LR5Gllazir8H7Tcpx+2dm+vrqVXHUwMDBmpVx1MDAxZNRyM01PlFx1MDAwNFx1MDAwNIaC9lx1MDAwN9+uIXqJIaZcZkFcdTAwMTFnnFx0TClcdTAwMTYxxGSSXHUwMDFjf+Ppib9cdTAwMWJDRFx1MDAwNItQkUhCaM34NueEI6wzzYbPODOx5nZ9uztcZldtTqYlLsC+vVx1MDAxMJ3jOj1lx5NL/77kTlx1MDAxZU5cdTAwMWG32Vx1MDAxZKhcZvyfJlhcbq1cYuM4QrdgwlBcdTAwMTAkXHUwMDAy2YxzhkiMbsVcck24hlx1MDAwZZdcdTAwMDTL95KGvbFcdTAwMDHCXHUwMDE35Fx1MDAxMeWaiWfvSnlcdTAwMWL2WU1YqZNcdTAwMTJ+PfYxaElccuyT2Lq5wJmwNPiV0FTQTCudXuw9e3Uq0Ghv0nPbZ6Z7tFs6XHUwMDFk3OBs3pMxg7Eg64OJwiF7Xi7rJFxcSYVcdTAwMTCjOrRueek7k2ZcdTAwMTC9te/8zfjhhFx1MDAxMcU0SpzVndr7QnRKXHUwMDE1JyRLtiCz6+xNt4ZeXHUwMDBlZ3QvqK6K26PWZDLpVPx7Wrzj3vR80s9ENSPCXHUwMDAwPYlcdTAwMDTUXHUwMDE5ojJCNVx1MDAwM8WAlFIoWC4jw2HScpXcO2D9e65YXHUwMDAwqY+pir88qlx1MDAxMFx1MDAxZT2OJsKCd7lcdTAwMTBBMr1RKiPbXHLv8U1rXHUwMDFmxLVcXMP11cxcdTAwMWS1XHUwMDFm3Gvb8/fuqrf3pmLbXHQxVVx1MDAwMtdQu1x1MDAwNlx1MDAwNUlcdTAwMDD0UqbBPUfAxlx1MDAxMOBrqYJVOIFYj4NcdTAwMWSeq/OH7Fx1MDAxN5DNXHUwMDE4gjA27EpWYKevytOKUk15plx1MDAxMcysK3HsuuVu9Vx1MDAwMG/3+Vx1MDAwYjI+jPFPj9mJgtnrlX3TXHUwMDBmji2Ih0q3649lWj1cZjyCNd5NXjNcdTAwMTIsXHUwMDFi+Vx1MDAxNPzmv/9cdTAwMDFcdTAwMDQgQjsifQ==<!-- payload-end -->
+ <defs>
+ <style>
+ @font-face {
+ font-family: "Virgil";
+ src: url("https://excalidraw.com/Virgil.woff2");
+ }
+ @font-face {
+ font-family: "Cascadia";
+ src: url("https://excalidraw.com/Cascadia.woff2");
+ }
+ </style>
+ </defs>
+ <rect x="0" y="0" width="571.8889058430991" height="551.2222391764319" fill="#ffffff"></rect><g stroke-linecap="round" transform="translate(10 10) rotate(0 275.94445292154955 265.61111958821596)"><path d="M0 0 C140.46 0, 280.92 0, 551.89 0 M0 0 C204.72 0, 409.45 0, 551.89 0 M551.89 0 C551.89 152.39, 551.89 304.77, 551.89 531.22 M551.89 0 C551.89 107.04, 551.89 214.08, 551.89 531.22 M551.89 531.22 C332.47 531.22, 113.04 531.22, 0 531.22 M551.89 531.22 C417.98 531.22, 284.07 531.22, 0 531.22 M0 531.22 C0 418.2, 0 305.18, 0 0 M0 531.22 C0 346.7, 0 162.17, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(85.44442749023415 48.555572509765625) rotate(0 142 16)"><text x="0" y="26" font-family="Helvetica, Segoe UI Emoji" font-size="28px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Reward created successfully</text></g><g transform="translate(65.88732457160927 145.118741350042) rotate(0 33.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">amount</text></g><g stroke-linecap="round" transform="translate(267.5406907399499 142.480934712235) rotate(0 77.99999999999989 14.152236652236752)"><path d="M0 0 C55.83 0, 111.67 0, 156 0 M0 0 C38.38 0, 76.75 0, 156 0 M156 0 C156 7.9, 156 15.79, 156 28.3 M156 0 C156 10.3, 156 20.6, 156 28.3 M156 28.3 C117.29 28.3, 78.59 28.3, 0 28.3 M156 28.3 C96.97 28.3, 37.93 28.3, 0 28.3 M0 28.3 C0 21.43, 0 14.55, 0 0 M0 28.3 C0 22.04, 0 15.77, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(66.88732457160927 204.63380306959152) rotate(0 49.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">justification</text></g><g transform="translate(73.66508539517713 338.18934167093744) rotate(0 33.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">reward URL</text></g><g stroke-linecap="round" transform="translate(206.4295796288386 142.52151912781937) rotate(0 30.5 14.097222222222399)"><path d="M0 0 C14.45 0, 28.9 0, 61 0 M0 0 C13.99 0, 27.98 0, 61 0 M61 0 C61 10.08, 61 20.16, 61 28.19 M61 0 C61 7.45, 61 14.91, 61 28.19 M61 28.19 C41.93 28.19, 22.86 28.19, 0 28.19 M61 28.19 C41.66 28.19, 22.33 28.19, 0 28.19 M0 28.19 C0 21.41, 0 14.63, 0 0 M0 28.19 C0 20.05, 0 11.91, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(213.09624629550513 145.118741350042) rotate(0 21 11.5)"><text x="21" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">USD</text></g><g stroke-linecap="round" transform="translate(206.4295796288386 207.92332482337952) rotate(0 134.84126984126988 51.111111111111086)"><path d="M0 0 C97.82 0, 195.63 0, 269.68 0 M0 0 C87.58 0, 175.15 0, 269.68 0 M269.68 0 C269.68 23.55, 269.68 47.1, 269.68 102.22 M269.68 0 C269.68 38.76, 269.68 77.52, 269.68 102.22 M269.68 102.22 C168.96 102.22, 68.23 102.22, 0 102.22 M269.68 102.22 C192.45 102.22, 115.21 102.22, 0 102.22 M0 102.22 C0 63.99, 0 25.75, 0 0 M0 102.22 C0 69.03, 0 35.84, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(205.3184685177273 334.0422606998018) rotate(0 85.37038167317712 15)"><path d="M0 0 C58.97 0, 117.94 0, 170.74 0 M0 0 C66.44 0, 132.88 0, 170.74 0 M170.74 0 C170.74 9.84, 170.74 19.67, 170.74 30 M170.74 0 C170.74 11.46, 170.74 22.92, 170.74 30 M170.74 30 C111.07 30, 51.39 30, 0 30 M170.74 30 C121.68 30, 72.63 30, 0 30 M0 30 C0 21.78, 0 13.56, 0 0 M0 30 C0 20.57, 0 11.13, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(76.67993668715121 404.7879712581632) rotate(0 41.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">valid until</text></g><g stroke-linecap="round" transform="translate(212.71710211484606 392.3770074341571) rotate(0 71.39795918367349 18.459183673469397)"><path d="M0.56 1.22 L141.57 0.94 L141.78 38.25 L-1.25 38.38" stroke="none" stroke-width="0" fill="#fff"></path><path d="M-0.98 1.62 C34.12 -1.49, 68.83 -1.89, 142.94 -0.88 M0.57 -0.59 C29.47 0.89, 57.16 -0.08, 142.07 0.14 M142.91 -0.64 C143.04 15.1, 140.92 25.51, 142.3 36.46 M141.87 -0.37 C142.21 8.72, 143.63 15.39, 141.94 37.29 M144.77 37.32 C105.38 36.8, 65.06 35.87, 0.85 37.03 M142.32 37.91 C86.66 35.41, 32.17 35.36, 0.24 37.86 M1.37 35.32 C1.21 25.05, 1.19 10.31, -0.4 -0.05 M-0.02 37.73 C0.2 26.83, -0.88 18.04, -0.59 0.08" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(247.36506129851932 398.8361911076265) rotate(0 5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g transform="translate(277.8650612985193 398.3361911076265) rotate(0 5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">/</text></g><g stroke-linecap="round" transform="translate(366.8650612985193 391.3361911076265) rotate(0 17.75 17.75)"><path d="M0.94 -1.01 L36.83 -1.25 L36.96 34.45 L-0.83 36.6" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-1.6 -0.35 C6.91 0.23, 16.94 -1.91, 34.19 0.08 M0.95 -0.04 C12.64 -1.04, 25.48 0.32, 34.73 -0.09 M37.19 -1.59 C34.07 10.35, 34.93 20.04, 35.6 37.4 M36.19 0.82 C34.7 6.51, 35.74 14.48, 34.58 35.73 M35.05 35.71 C19.96 36.63, 7.29 37.51, -0.4 33.62 M35.33 35.31 C26.31 35.42, 18.5 35.89, -0.89 34.55 M1.85 36.37 C1.11 22.03, 0.24 8.62, 1.34 1.61 M-0.36 34.87 C0.29 24.35, -0.21 14.65, 0.61 -0.61" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(367.8650612985193 392.3361911076265) rotate(0 17.5 4.5)"><path d="M-1.01 1.33 L33.75 1.46 L33.95 8.17 L1.1 7.74" stroke="none" stroke-width="0" fill="#000"></path><path d="M-0.35 -2 C13.48 -0.6, 24.68 -1.03, 35.08 1.14 M-0.04 -0.02 C7.69 -0.19, 17.48 -1.1, 34.91 0.05 M34.28 -0.59 C34.8 2.2, 34.28 4.86, 35.86 8.17 M35.37 -0.3 C34.56 2.54, 34.82 4.33, 35.1 9.44 M35.21 7.62 C24.64 9.03, 14.32 8.52, -1.88 8.05 M34.81 8.78 C21.27 9.88, 7.77 8.05, -0.95 9.68 M0.39 9.37 C-0.22 7, -0.37 5.64, 0.73 -0.02 M-0.28 9.26 C-0.31 5.6, 0.09 2.41, -0.28 0.21" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(375.3650612985193 383.8361911076265) rotate(0 3 7)"><path d="M1.33 -1.25 L7.46 -1.05 L5.17 15.1 L-1.26 12.71" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M-0.6 0.04 C1.4 -0.59, 2.93 0.04, 6.34 -0.36 M-0.01 -0.22 C2.36 0.19, 4.41 -0.02, 6.02 -0.1 M5.08 -0.34 C5.8 3.42, 6.19 10.47, 4.71 13.49 M5.53 -0.6 C6.36 3.16, 5.45 6.86, 6.69 14.14 M5.59 14.26 C3.76 14.53, 1.34 13.44, -0.28 14.6 M5.93 14.07 C5.03 14.2, 3.24 13.7, 0.21 13.76 M0.58 13.72 C-0.16 8.67, 0.81 5.49, -0.03 1.14 M0.41 13.59 C0.11 9.37, 0.48 3.91, 0.33 -0.35" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(390.3650612985193 383.8361911076265) rotate(0 3 7)"><path d="M-1.25 1.46 L4.95 -0.83 L7.1 12.74 L-1.29 14.58" stroke="none" stroke-width="0" fill="#868e96"></path><path d="M0.04 -0.26 C0.72 -0.33, 2.67 0.4, 5.64 0.52 M-0.22 0.04 C2.56 -0.23, 4.71 0.02, 5.9 0.08 M5.66 -0.32 C4.73 5.45, 7.22 9.47, 5.49 13.15 M5.4 0.26 C5.93 4.52, 6.28 11.02, 6.14 14.55 M6.26 14.03 C4.85 13.84, 2.11 13.67, 0.6 13.45 M6.07 14.28 C4.52 13.72, 2.32 14.19, -0.24 14.13 M-0.28 13.97 C-0.57 9.44, 1.07 2.97, 1.14 0.63 M-0.41 14.06 C0.28 10.73, -0.34 6.93, -0.35 0.47" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(383.8650612985193 400.3361911076265) rotate(0 0.6422718642013479 13.197904566302896)"><path d="M-0.88 -1.99 C-1.43 7.57, 1.15 13.78, 2.24 28.39 M0.14 0.63 C-0.63 7.75, 0.34 15.35, 0.76 27.34" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g stroke-linecap="round"><g transform="translate(374.3650612985193 399.3361911076265) rotate(0 0.19790456630289555 13.301320007070899)"><path d="M-1.99 -1.31 C0.2 6.74, -0.97 12.94, 2.39 27.91 M0.63 -0.77 C-0.14 8.39, -0.23 16.93, 1.34 27.2" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g stroke-linecap="round"><g transform="translate(393.8650612985193 400.8361911076265) rotate(0 0.2720004984978459 12.683548028115183)"><path d="M-1.31 0.08 C1.49 6.67, 2.55 17.58, 1.41 25.45 M-0.77 -0.09 C0.43 5.46, 0.98 12.41, 0.7 24.84" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g stroke-linecap="round"><g transform="translate(402.8650612985193 408.8361911076265) rotate(0 -17.287554731126875 -0.13689562075796857)"><path d="M0.08 1.14 C-9.9 1.52, -15.53 -0.31, -34.05 -1.46 M-0.09 0.05 C-10.99 0, -20.5 -1.06, -34.66 -0.25" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g stroke-linecap="round"><g transform="translate(402.3650612985193 417.8361911076265) rotate(0 -18.16205287910998 0.04547248221933842)"><path d="M1.14 -1.19 C-5.48 2.11, -14.51 0.37, -37.46 1.28 M0.05 -0.32 C-12.82 1.18, -26.96 0.04, -36.25 0.77" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g stroke-linecap="round" transform="translate(340.7275521017252 468.94674259140356) rotate(0 68.33333333333326 18.888905843098996)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.26 6.4 C1.09 4.84, 2.44 3.29, 4.99 0.36 M-0.26 6.4 C1.46 4.42, 3.17 2.45, 4.99 0.36 M0.13 12.04 C2.6 9.2, 5.07 6.36, 10.63 -0.03 M0.13 12.04 C2.36 9.48, 4.59 6.92, 10.63 -0.03 M-0.13 18.44 C3.98 13.71, 8.09 8.98, 15.62 0.33 M-0.13 18.44 C3.41 14.36, 6.95 10.29, 15.62 0.33 M0.27 24.08 C6 17.49, 11.72 10.9, 21.26 -0.07 M0.27 24.08 C7.46 15.81, 14.65 7.53, 21.26 -0.07 M0 30.48 C5.48 24.19, 10.95 17.89, 26.25 0.29 M0 30.48 C9.05 20.07, 18.1 9.66, 26.25 0.29 M-0.26 36.88 C8.64 26.64, 17.54 16.41, 31.89 -0.1 M-0.26 36.88 C12.31 22.42, 24.88 7.96, 31.89 -0.1 M2.11 40.26 C13.59 27.05, 25.06 13.85, 36.88 0.26 M2.11 40.26 C12.5 28.3, 22.9 16.34, 36.88 0.26 M7.75 39.86 C19.43 26.42, 31.11 12.99, 42.52 -0.14 M7.75 39.86 C18.98 26.94, 30.22 14.01, 42.52 -0.14 M12.74 40.22 C24.86 26.28, 36.98 12.33, 47.51 0.22 M12.74 40.22 C20.81 30.93, 28.89 21.64, 47.51 0.22 M18.38 39.83 C31.65 24.56, 44.91 9.3, 53.15 -0.17 M18.38 39.83 C28.39 28.31, 38.41 16.79, 53.15 -0.17 M23.37 40.19 C36.54 25.03, 49.71 9.88, 58.14 0.19 M23.37 40.19 C34.58 27.29, 45.8 14.38, 58.14 0.19 M29.01 39.79 C38.99 28.31, 48.97 16.82, 63.78 -0.21 M29.01 39.79 C40.04 27.1, 51.07 14.42, 63.78 -0.21 M34 40.15 C41.91 31.05, 49.83 21.94, 68.77 0.15 M34 40.15 C43.74 28.94, 53.49 17.73, 68.77 0.15 M39.64 39.76 C52.44 25.03, 65.24 10.31, 74.41 -0.24 M39.64 39.76 C47.47 30.75, 55.31 21.73, 74.41 -0.24 M44.63 40.12 C54.86 28.34, 65.1 16.57, 79.4 0.12 M44.63 40.12 C53.28 30.16, 61.94 20.2, 79.4 0.12 M50.27 39.72 C60.09 28.43, 69.91 17.13, 85.04 -0.28 M50.27 39.72 C61.03 27.34, 71.8 14.96, 85.04 -0.28 M55.26 40.08 C64.66 29.27, 74.06 18.46, 90.03 0.08 M55.26 40.08 C65.85 27.89, 76.45 15.7, 90.03 0.08 M60.9 39.69 C72.37 26.49, 83.85 13.29, 95.67 -0.31 M60.9 39.69 C69.59 29.69, 78.29 19.68, 95.67 -0.31 M65.89 40.05 C74.2 30.49, 82.51 20.92, 100.66 0.05 M65.89 40.05 C78.29 25.78, 90.69 11.52, 100.66 0.05 M71.53 39.65 C83.8 25.54, 96.08 11.42, 106.3 -0.34 M71.53 39.65 C78.82 31.27, 86.11 22.88, 106.3 -0.34 M76.52 40.01 C89.61 24.96, 102.7 9.9, 111.29 0.02 M76.52 40.01 C85.09 30.16, 93.66 20.3, 111.29 0.02 M82.16 39.62 C90.2 30.37, 98.24 21.12, 116.27 0.38 M82.16 39.62 C93.56 26.5, 104.97 13.38, 116.27 0.38 M87.15 39.98 C95.85 29.97, 104.55 19.96, 121.92 -0.02 M87.15 39.98 C95.8 30.03, 104.45 20.07, 121.92 -0.02 M92.79 39.59 C99.78 31.55, 106.76 23.51, 126.91 0.34 M92.79 39.59 C101.4 29.69, 110 19.78, 126.91 0.34 M97.78 39.95 C108.93 27.11, 120.09 14.28, 132.55 -0.05 M97.78 39.95 C110.68 25.1, 123.59 10.25, 132.55 -0.05 M103.42 39.55 C114.64 26.64, 125.86 13.73, 137.54 0.31 M103.42 39.55 C116.21 24.83, 129.01 10.11, 137.54 0.31 M108.41 39.91 C115.34 31.93, 122.28 23.95, 137.27 6.7 M108.41 39.91 C115.74 31.48, 123.06 23.05, 137.27 6.7 M114.05 39.52 C119.08 33.73, 124.11 27.95, 137.01 13.1 M114.05 39.52 C123.16 29.04, 132.27 18.56, 137.01 13.1 M119.04 39.88 C125.53 32.41, 132.02 24.95, 137.41 18.74 M119.04 39.88 C123.99 34.17, 128.95 28.47, 137.41 18.74 M124.02 40.24 C128.33 35.28, 132.63 30.33, 137.15 25.14 M124.02 40.24 C129.2 34.28, 134.37 28.33, 137.15 25.14 M129.67 39.84 C132.79 36.25, 135.91 32.66, 137.54 30.79 M129.67 39.84 C131.44 37.8, 133.21 35.77, 137.54 30.79" stroke="#82c91e" stroke-width="0.5" fill="none"></path><path d="M0 0 C49.47 0, 98.93 0, 136.67 0 M0 0 C42.29 0, 84.59 0, 136.67 0 M136.67 0 C136.67 8.33, 136.67 16.66, 136.67 37.78 M136.67 0 C136.67 8.06, 136.67 16.12, 136.67 37.78 M136.67 37.78 C93.85 37.78, 51.03 37.78, 0 37.78 M136.67 37.78 C88.21 37.78, 39.74 37.78, 0 37.78 M0 37.78 C0 24.21, 0 10.64, 0 0 M0 37.78 C0 27.5, 0 17.22, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(372.94974041552723 475.50226423853906) rotate(0 37.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">continue</text></g><g stroke-linecap="round" transform="translate(388.95413517850125 333.70723212274766) rotate(0 42.96295166015625 15.66137767973396)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.26 6.4 C1.33 4.57, 2.92 2.74, 4.99 0.36 M-0.26 6.4 C1.67 4.17, 3.61 1.95, 4.99 0.36 M0.13 12.04 C4.31 7.24, 8.49 2.43, 10.63 -0.03 M0.13 12.04 C4.25 7.31, 8.36 2.58, 10.63 -0.03 M-0.13 18.44 C4.4 13.23, 8.93 8.02, 15.62 0.33 M-0.13 18.44 C6.09 11.29, 12.3 4.14, 15.62 0.33 M0.27 24.08 C6.1 17.37, 11.93 10.66, 21.26 -0.07 M0.27 24.08 C8.03 15.15, 15.79 6.22, 21.26 -0.07 M0 30.48 C7.44 21.92, 14.88 13.36, 26.25 0.29 M0 30.48 C9.23 19.87, 18.45 9.26, 26.25 0.29 M2.37 33.86 C8.28 27.06, 14.18 20.27, 31.89 -0.1 M2.37 33.86 C11.1 23.81, 19.83 13.77, 31.89 -0.1 M8.01 33.46 C18.87 20.98, 29.72 8.49, 36.88 0.26 M8.01 33.46 C15.44 24.92, 22.87 16.37, 36.88 0.26 M13 33.82 C24.34 20.78, 35.68 7.73, 42.52 -0.14 M13 33.82 C20.91 24.72, 28.83 15.61, 42.52 -0.14 M18.64 33.43 C27.12 23.68, 35.59 13.93, 47.51 0.22 M18.64 33.43 C27.73 22.98, 36.81 12.53, 47.51 0.22 M23.63 33.79 C30.77 25.58, 37.9 17.37, 53.15 -0.17 M23.63 33.79 C30.05 26.4, 36.47 19.01, 53.15 -0.17 M29.27 33.39 C38.11 23.22, 46.96 13.05, 58.14 0.19 M29.27 33.39 C35.28 26.48, 41.29 19.57, 58.14 0.19 M34.26 33.75 C42.43 24.35, 50.6 14.95, 63.78 -0.21 M34.26 33.75 C40.39 26.7, 46.52 19.64, 63.78 -0.21 M39.9 33.36 C49.33 22.51, 58.76 11.66, 68.77 0.15 M39.9 33.36 C45.83 26.54, 51.75 19.73, 68.77 0.15 M44.89 33.72 C56.26 20.63, 67.64 7.55, 74.41 -0.24 M44.89 33.72 C54.79 22.33, 64.69 10.95, 74.41 -0.24 M50.53 33.33 C56.58 26.37, 62.62 19.42, 79.4 0.12 M50.53 33.33 C57.93 24.81, 65.34 16.29, 79.4 0.12 M55.52 33.69 C66.01 21.61, 76.51 9.54, 85.04 -0.28 M55.52 33.69 C62.29 25.89, 69.07 18.1, 85.04 -0.28 M61.16 33.29 C67.92 25.51, 74.68 17.74, 88.06 2.35 M61.16 33.29 C69.1 24.16, 77.03 15.03, 88.06 2.35 M66.15 33.65 C74.36 24.21, 82.56 14.77, 88.45 7.99 M66.15 33.65 C74.01 24.61, 81.87 15.57, 88.45 7.99 M71.79 33.26 C76.57 27.76, 81.35 22.26, 88.19 14.39 M71.79 33.26 C77.32 26.9, 82.85 20.54, 88.19 14.39 M76.78 33.62 C80.26 29.61, 83.75 25.6, 88.59 20.03 M76.78 33.62 C80.31 29.55, 83.84 25.49, 88.59 20.03 M82.42 33.22 C83.67 31.79, 84.91 30.35, 88.33 26.43 M82.42 33.22 C84.67 30.63, 86.92 28.04, 88.33 26.43" stroke="#4c6ef5" stroke-width="0.5" fill="none"></path><path d="M0 0 C34.37 0, 68.73 0, 85.93 0 M0 0 C30.8 0, 61.6 0, 85.93 0 M85.93 0 C85.93 7.3, 85.93 14.59, 85.93 31.32 M85.93 0 C85.93 10.75, 85.93 21.51, 85.93 31.32 M85.93 31.32 C64.61 31.32, 43.3 31.32, 0 31.32 M85.93 31.32 C64.26 31.32, 42.59 31.32, 0 31.32 M0 31.32 C0 19.26, 0 7.2, 0 0 M0 31.32 C0 20.81, 0 10.29, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(396.7054353242104 338.1304988211914) rotate(0 35 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">copy url</text></g><g transform="translate(78.68102157642033 106.96052345493217) rotate(0 20 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">from</text></g><g transform="translate(211.63556703096583 97.86961436402316) rotate(0 71.5 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">video promotion</text></g></svg> \ No newline at end of file
diff --git a/images/backoffice-reward-create.svg b/images/backoffice-reward-create.svg
new file mode 100644
index 00000000..acdbf0e6
--- /dev/null
+++ b/images/backoffice-reward-create.svg
@@ -0,0 +1,16 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 493 527.3333587646484" width="493" height="527.3333587646484">
+ <!-- svg-source:excalidraw -->
+ <!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO2aXXPaOFx1MDAxNIbv91cw7O3G1dG3etc0JGnzVSBtmuzsZFx1MDAxY2PAwbHBNlx1MDAxMLLT/77HJlx1MDAwNVx1MDAwN2xK0iXlorpgQLaQLD169Z5cdTAwMDP//lGpVJNJ362+rVTde8f2vVZkj6t/pfUjN4q9MMBLNPtcdTAwMWOHw8jJ7uwmST9+++bNvIXlhHfTVq7v3rlBXHUwMDEy431/4+dK5d/sNddP5DqJXHUwMDFkdHw3a5BdmnfFQCzWnoZB1i1oqqkkVKrZXHUwMDFkXryH/SVuXHUwMDBiL7dtP3bnV9KqKmlDg1+2duv7XVVzj+Wnzu7Vh3m3bc/3m8nEnz6U7XSHUW5QcVx1MDAxMoU998JrJd2094X6Wbs4xCmYt4rCYadcdTAwMWK4cTpcdTAwMDFkVlx1MDAxYvZtx0sm6feQee10XHUwMDE28vfd4yfFhUVBKo4vXFxcYq1nV7P2jCqLS05AMc2FpotcdTAwMDN7XHUwMDFm+mGUXHUwMDBl7E+SlfnQbmyn18HxXHUwMDA1rdk9SWRcdTAwMDdx345wxeb3jVx1MDAxZlx1MDAxZpkrNqvrul6nm2ClIMpiWIRWXHUwMDEyh6H5vHs3W1x1MDAwN+BCXHUwMDExQ7iaL2Taaf9DK2Pin8V57NpR/3G+qnH6ITfgdKy1KVDfm2fXvv1VjFbi3idFVIHRpVRcdTAwMDFcdTAwMTDNmDLrU9Wpx/bt6WDiXHUwMDA0t0fRuLFvjztf9l+PKnhcdTAwMTFVmlx1MDAxMktKXHUwMDAwaaTgyjC6QJWUXHUwMDE2XHUwMDAxI7TRhjOu1MaoXHUwMDAyWUBVbjiPXHUwMDE4aWq0MpyajVA0X6wwSJreQzpfVD+p3bfvPH/yXf2mmKV4YVx1MDAwN++GSTeMsFXl3Mt3ZMeu71x1MDAwNdl3iSeN3vleJ+Ww6rvtp4AmXHUwMDFlSujsclx1MDAxMvarL1x1MDAwMpzyUtlcdTAwMTTMXHUwMDEwokluO/6I76ZkX6+b8eee09o9csjHi1x1MDAxZMHb266amoBcdTAwMDWEXHUwMDEzKVx1MDAxNZMgNXvKN5fUQrFUKFtcZt+zzfGdO55meFO2iLdSlHNcdTAwMDNcZl5cdTAwMGZvsi7e9lx1MDAxZH5lUsg16M1wvdpcdTAwMTMoXlx1MDAwNjfKXHUwMDE5Z4Zqsj7dSe2hW+veXn4hjeaZX2vRXHUwMDExnD1sO914XHUwMDA3tZRQnFE8Wlx1MDAwNdFyXHUwMDAxb2Esg0BcdEqM1LBB9Vx1MDAxNsIyuaKKaNdcdTAwMTYjXHUwMDFj3cP0VSxpO1A0MVTBXHUwMDE2OVx1MDAwNFxupIwxo6jG3UrXN1xisX/Waun43VFcdTAwMTLQ+vveUVxy6l/6246YRsJWXGKooNRcIkahjeCCo/eUXHUwMDFiQ8yYXHUwMDAypJZcdTAwMDRcdTAwMTTAXHUwMDE4aqhcdTAwMTTbqKC3wzjx2iiBSUrXa1xuaSnfrNxcdTAwMDFcdTAwMTPcp5JcdTAwMDCBtVx1MDAwMb84XGZvO3bg9O5P9mpHV/HhXHUwMDE5xHT7XHUwMDAx51x1MDAxNsezXHUwMDA04ZRGkJxIZu3RXHUwMDE2W4JTijGN0Vx1MDAxMoPNzWkowFqEK1xcXHUwMDE2yslmVPLnXHUwMDAw/9w4rtjtxI0qSYlcdTAwMDP+NU5hXHUwMDA15VxmXHUwMDBmXHUwMDFkTZhZ3ylcdTAwMDSDwO7tnXbPrpvn3v7koj+x+4fbTrnhYGFgzihgkMdMzjrNjYJcdTAwMTaCoXBcIlvANka5XHUwMDA0i+RLXHUwMDEx89pcdTAwMDJ0Ld+Lyq3NbFx1MDAwZjD0yYKJV7RcbtPFP5lcdTAwMWM0xMfk8POVe/yhpmvMY040/7ZivZ0uXHUwMDAw2lx1MDAxZsDoVaOoXHUwMDEyuTj/pXHILOtCXHUwMDBiJoqtWPX/a+F+Nc8vXdhZ3omhb+Egllwi4cxxwmLtXFxcdTAwMTiwJdpmNp/jcmFYhihcdTAwMTj6/rI8Nvdy8/pcXIGdiaGDvbjRXG61vPNarbxcdTAwMTI+0d9cdTAwMTVwXHUwMDBmh/W929Od1nWbXe80ertn51x1MDAxN/FgXHUwMDE57lx1MDAwMq1dQ2JcdTAwMDRcdTAwMTVcdTAwMTZL8aaUKINLsoQ4pVx1MDAxOKvnyzLxgG6U5krutP69XHUwMDAzSnaARGE3kpsl1FPzU3owUkY0XHUwMDE3UppcdTAwMTfjv1x1MDAwMrRJR1xmdmv3XHUwMDAzICeNg+7O8Ct1O1x1MDAxZp9cdTAwMDFcdTAwMWGxUPsxNpOaUi1cdTAwMTdylniEWYJIqjQ+XHUwMDAx06xcdTAwMDA0UJbKXHUwMDE1XZR6XFx1ov4mK6NcdTAwMDBcdTAwMTExWqG4XHUwMDE2SauUpWjh+Vx1MDAwN5TytXKPz2BrLS9cYsKUjSvNgVx1MDAwYvqMnFG9OVKj4+H4obu7XHUwMDA38sTeXHUwMDFmQFx1MDAxYrZndctyRpRbTDGDno9cdEbEQkSvJF7G9Vx1MDAwMYGSIdlPxTt/aupcdTAwMThwl10gMGnJXFxcdTAwMTFcdTAwMDXuhmWbVFx1MDAwM0iMu4zKxf/fj3aGXHUwMDE3uNS5J/jlXHSj/PwvOlxuXHUwMDAxaW6Xs/VcdTAwMDG7dO6vhrs6OGdccv35MLxcdTAwMWONXHUwMDBmXHUwMDA34+1cdTAwMDdMSFx1MDAwYk9cdTAwMWPAo1x1MDAxZZ+XLFx1MDAwNNRKXHUwMDExXHUwMDBiwVJM4fopqfRGXHUwMDAwy9m9VbG04FJRkk/ibU8w7USunZS5uGJnuNEoXHUwMDFh6IooXHUwMDFhd2r6Y+E6bmGK9rt6r9mbfNE3XHUwMDA3XHUwMDEzV53S9/WHJrnadrQ1/4F0Mkug71x1MDAxMFxiXHUwMDE1uq5cciZD/1x1MDAxN/2kwmA1hvzbI5+y9HBGMTFEkGeIp7czuqt9fDiO7u6u6no0qN+44nbrXHRTT7VcdTAwMTNcdTAwMTZcYkPxzP6XoJniXHUwMDAwZnN5XHUwMDFhoZeJKkpGgjRqS9Ptjo3o+K9cIqBT4lx1MDAwZW9cdTAwMGU6XHUwMDBmXHL302nLXHUwMDBiXHUwMDFjR4zGo4frg3WSQ8ooS1xigedcdTAwMTBJT0a+cGRyMFx1MDAxNu5hwcBcYsJze32WXHUwMDFjXCIrXHUwMDE363dcdTAwMDBTXHUwMDEywFx1MDAxOFx1MDAwMaDxXFwrylxy0dJflynR2jDKxctj4yVW29HjP+VehvtzXHUwMDAwLtxcdTAwMGZqXHUwMDA11uRcXN9cZm6O9OBSXFzu8Xup7qPwcr2cp7SQXVwiXHUwMDE501x1MDAwNP3eQqDOKViUivRHReA4p2KJazTLv8F+XHTYKaLpv+1IXHUwMDEx2az8v5RcbrBcdTAwMTnP/3vwp8lcdTAwMWV5LTes9JHv8OnPnr9cZnJ8zaa0avf7zST12G9cdTAwMWaRx2n3Wo9jmj9cZj6CO94tXGI+2llJT4Rvf3z7XHUwMDBmXHUwMDBlXHUwMDE54yoifQ==<!-- payload-end -->
+ <defs>
+ <style>
+ @font-face {
+ font-family: "Virgil";
+ src: url("https://excalidraw.com/Virgil.woff2");
+ }
+ @font-face {
+ font-family: "Cascadia";
+ src: url("https://excalidraw.com/Cascadia.woff2");
+ }
+ </style>
+ </defs>
+ <rect x="0" y="0" width="493" height="527.3333587646484" fill="#ffffff"></rect><g stroke-linecap="round" transform="translate(10 10) rotate(0 236.5 253.66667938232422)"><path d="M0 0 C131.16 0, 262.31 0, 473 0 M0 0 C111.95 0, 223.9 0, 473 0 M473 0 C473 107.96, 473 215.91, 473 507.33 M473 0 C473 117.77, 473 235.54, 473 507.33 M473 507.33 C367.62 507.33, 262.25 507.33, 0 507.33 M473 507.33 C343.17 507.33, 213.33 507.33, 0 507.33 M0 507.33 C0 342.58, 0 177.83, 0 0 M0 507.33 C0 399.36, 0 291.39, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(85.44442749023438 48.555572509765625) rotate(0 81.5 16)"><text x="0" y="25" font-family="Helvetica, Segoe UI Emoji" font-size="28px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Authorize Reward</text></g><g transform="translate(65.8873245716095 145.11874135004155) rotate(0 33.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">amount</text></g><g stroke-linecap="round" transform="translate(267.5406907399498 142.48093471223478) rotate(0 77.99999999999983 14.152236652236752)"><path d="M0 0 C59.79 0, 119.57 0, 156 0 M0 0 C43.47 0, 86.93 0, 156 0 M156 0 C156 6.15, 156 12.31, 156 28.3 M156 0 C156 10.96, 156 21.92, 156 28.3 M156 28.3 C104.75 28.3, 53.51 28.3, 0 28.3 M156 28.3 C108.41 28.3, 60.82 28.3, 0 28.3 M0 28.3 C0 20.46, 0 12.62, 0 0 M0 28.3 C0 20.37, 0 12.43, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(66.8873245716095 204.63380306959152) rotate(0 49.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">justification</text></g><g transform="translate(69.22065790494287 337.0782475140361) rotate(0 55.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">URL after reward</text></g><g stroke-linecap="round" transform="translate(206.4295796288386 142.52151912781915) rotate(0 30.5 14.097222222222399)"><path d="M0 0 C21.91 0, 43.82 0, 61 0 M0 0 C15.53 0, 31.06 0, 61 0 M61 0 C61 7.5, 61 15.01, 61 28.19 M61 0 C61 8.02, 61 16.03, 61 28.19 M61 28.19 C42.22 28.19, 23.45 28.19, 0 28.19 M61 28.19 C45.87 28.19, 30.75 28.19, 0 28.19 M0 28.19 C0 17.6, 0 7, 0 0 M0 28.19 C0 20.22, 0 12.24, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(213.09624629550524 145.11874135004155) rotate(0 21 11.5)"><text x="21" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">USD</text></g><g stroke-linecap="round" transform="translate(206.4295796288386 207.9233248233793) rotate(0 110.55555555555554 51.111111111111086)"><path d="M0 0 C44.54 0, 89.08 0, 221.11 0 M0 0 C71.21 0, 142.42 0, 221.11 0 M221.11 0 C221.11 37.99, 221.11 75.97, 221.11 102.22 M221.11 0 C221.11 30.08, 221.11 60.16, 221.11 102.22 M221.11 102.22 C157.92 102.22, 94.74 102.22, 0 102.22 M221.11 102.22 C136.25 102.22, 51.39 102.22, 0 102.22 M0 102.22 C0 70.18, 0 38.13, 0 0 M0 102.22 C0 65.3, 0 28.38, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(205.3184685177274 334.0422606998013) rotate(0 108.88888888888886 15)"><path d="M0 0 C60.68 0, 121.36 0, 217.78 0 M0 0 C47.35 0, 94.7 0, 217.78 0 M217.78 0 C217.78 11.62, 217.78 23.23, 217.78 30 M217.78 0 C217.78 9.86, 217.78 19.71, 217.78 30 M217.78 30 C151.34 30, 84.91 30, 0 30 M217.78 30 C157.45 30, 97.12 30, 0 30 M0 30 C0 21.59, 0 13.18, 0 0 M0 30 C0 19.86, 0 9.71, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(289.1572037707465 446.8971981070499) rotate(0 68.33333333333326 18.888905843098996)"><path d="M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0 M-0.26 6.4 C0.87 5.1, 2 3.79, 4.99 0.36 M-0.26 6.4 C1.41 4.48, 3.08 2.56, 4.99 0.36 M0.13 12.04 C3.51 8.15, 6.89 4.27, 10.63 -0.03 M0.13 12.04 C3.27 8.43, 6.41 4.82, 10.63 -0.03 M-0.13 18.44 C4.49 13.13, 9.1 7.82, 15.62 0.33 M-0.13 18.44 C5.98 11.41, 12.1 4.37, 15.62 0.33 M0.27 24.08 C6.99 16.35, 13.71 8.62, 21.26 -0.07 M0.27 24.08 C6.62 16.77, 12.97 9.46, 21.26 -0.07 M0 30.48 C6.13 23.43, 12.26 16.38, 26.25 0.29 M0 30.48 C7.11 22.31, 14.22 14.13, 26.25 0.29 M-0.26 36.88 C8.61 26.67, 17.48 16.47, 31.89 -0.1 M-0.26 36.88 C9.73 25.39, 19.72 13.9, 31.89 -0.1 M2.11 40.26 C15.11 25.29, 28.12 10.33, 36.88 0.26 M2.11 40.26 C9.34 31.93, 16.58 23.61, 36.88 0.26 M7.75 39.86 C18.54 27.45, 29.32 15.04, 42.52 -0.14 M7.75 39.86 C21.47 24.07, 35.2 8.29, 42.52 -0.14 M12.74 40.22 C26.45 24.44, 40.17 8.66, 47.51 0.22 M12.74 40.22 C24.07 27.19, 35.39 14.16, 47.51 0.22 M18.38 39.83 C26.6 30.37, 34.82 20.92, 53.15 -0.17 M18.38 39.83 C30.86 25.47, 43.35 11.1, 53.15 -0.17 M23.37 40.19 C30.9 31.52, 38.44 22.85, 58.14 0.19 M23.37 40.19 C34.91 26.91, 46.46 13.62, 58.14 0.19 M29.01 39.79 C38.04 29.4, 47.08 19.01, 63.78 -0.21 M29.01 39.79 C37.38 30.16, 45.76 20.53, 63.78 -0.21 M34 40.15 C44.6 27.96, 55.19 15.77, 68.77 0.15 M34 40.15 C41.57 31.44, 49.14 22.73, 68.77 0.15 M39.64 39.76 C49.31 28.63, 58.98 17.51, 74.41 -0.24 M39.64 39.76 C46.94 31.36, 54.24 22.96, 74.41 -0.24 M44.63 40.12 C57.31 25.52, 70 10.93, 79.4 0.12 M44.63 40.12 C57.04 25.84, 69.45 11.56, 79.4 0.12 M50.27 39.72 C63.52 24.48, 76.77 9.23, 85.04 -0.28 M50.27 39.72 C59.63 28.95, 69 18.18, 85.04 -0.28 M55.26 40.08 C63.79 30.27, 72.32 20.45, 90.03 0.08 M55.26 40.08 C62.43 31.83, 69.6 23.58, 90.03 0.08 M60.9 39.69 C73.1 25.65, 85.3 11.62, 95.67 -0.31 M60.9 39.69 C73.22 25.52, 85.54 11.34, 95.67 -0.31 M65.89 40.05 C74.13 30.57, 82.37 21.09, 100.66 0.05 M65.89 40.05 C73.02 31.84, 80.15 23.64, 100.66 0.05 M71.53 39.65 C84.1 25.19, 96.67 10.73, 106.3 -0.34 M71.53 39.65 C79.65 30.32, 87.77 20.98, 106.3 -0.34 M76.52 40.01 C89.46 25.12, 102.41 10.23, 111.29 0.02 M76.52 40.01 C86.11 28.98, 95.7 17.95, 111.29 0.02 M82.16 39.62 C91.69 28.65, 101.23 17.69, 116.27 0.38 M82.16 39.62 C89.25 31.46, 96.35 23.3, 116.27 0.38 M87.15 39.98 C98.5 26.92, 109.86 13.86, 121.92 -0.02 M87.15 39.98 C98.39 27.04, 109.64 14.11, 121.92 -0.02 M92.79 39.59 C105.18 25.33, 117.58 11.07, 126.91 0.34 M92.79 39.59 C100.01 31.28, 107.23 22.97, 126.91 0.34 M97.78 39.95 C108.79 27.28, 119.8 14.61, 132.55 -0.05 M97.78 39.95 C109.46 26.51, 121.14 13.07, 132.55 -0.05 M103.42 39.55 C115.83 25.28, 128.23 11.01, 137.54 0.31 M103.42 39.55 C114.05 27.32, 124.68 15.1, 137.54 0.31 M108.41 39.91 C114.24 33.2, 120.08 26.48, 137.27 6.7 M108.41 39.91 C116.61 30.48, 124.8 21.05, 137.27 6.7 M114.05 39.52 C119.19 33.61, 124.32 27.7, 137.01 13.1 M114.05 39.52 C118.81 34.04, 123.56 28.57, 137.01 13.1 M119.04 39.88 C126.1 31.75, 133.17 23.62, 137.41 18.74 M119.04 39.88 C123.1 35.2, 127.17 30.53, 137.41 18.74 M124.02 40.24 C128.99 34.53, 133.95 28.81, 137.15 25.14 M124.02 40.24 C128.37 35.24, 132.71 30.24, 137.15 25.14 M129.67 39.84 C132.09 37.06, 134.51 34.27, 137.54 30.79 M129.67 39.84 C132.69 36.36, 135.71 32.89, 137.54 30.79" stroke="#82c91e" stroke-width="0.5" fill="none"></path><path d="M0 0 C47.02 0, 94.04 0, 136.67 0 M0 0 C39.95 0, 79.91 0, 136.67 0 M136.67 0 C136.67 7.93, 136.67 15.86, 136.67 37.78 M136.67 0 C136.67 9.75, 136.67 19.5, 136.67 37.78 M136.67 37.78 C85.5 37.78, 34.33 37.78, 0 37.78 M136.67 37.78 C97.93 37.78, 59.2 37.78, 0 37.78 M0 37.78 C0 26.23, 0 14.69, 0 0 M0 37.78 C0 30.21, 0 22.65, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(321.3793920845483 453.45271975418564) rotate(0 27.5 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">create</text></g><g stroke-linecap="round" transform="translate(109.15720377074649 446.0638393424015) rotate(0 68.33333333333326 18.888905843098996)"><path d="M0 0 C49.19 0, 98.37 0, 136.67 0 M0 0 C38.88 0, 77.76 0, 136.67 0 M136.67 0 C136.67 10.58, 136.67 21.17, 136.67 37.78 M136.67 0 C136.67 11.28, 136.67 22.55, 136.67 37.78 M136.67 37.78 C97.37 37.78, 58.07 37.78, 0 37.78 M136.67 37.78 C107.23 37.78, 77.8 37.78, 0 37.78 M0 37.78 C0 27.01, 0 16.24, 0 0 M0 37.78 C0 24.17, 0 10.57, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(141.37939208454827 452.6193609895372) rotate(0 29 11.5)"><text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">cancel</text></g><g transform="translate(62.3386848521759 102.39751456586987) rotate(0 20 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">from</text></g><g transform="translate(211.2023212158124 103.76115092950636) rotate(0 71.5 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">video promotion</text></g></svg> \ No newline at end of file
diff --git a/images/challenger.dot b/images/challenger.dot
new file mode 100644
index 00000000..d3072fc7
--- /dev/null
+++ b/images/challenger.dot
@@ -0,0 +1,26 @@
+digraph G {
+
+ user[label="Resource\nOwner"];
+ exchange[label="Client"];
+ messenger[label="Messaging service"];
+ challenger [label="Challenger HTTPD"];
+ helper [label="Helper script"];
+ DBMS [label="Postgres\nDBMS"];
+ subgraph cluster_0 {
+ challenger;
+ helper;
+ DBMS;
+ label="Challenger OAuth 2.0 service";
+ }
+ user->exchange[label="0. request that\nrequires\nvalidated\naddress"];
+ exchange->challenger[label="1. authorize\naddress\nvalidation"];
+ user->challenger[label="2. Claimed\naddress"];
+ challenger->DBMS;
+ DBMS->challenger;
+ challenger->helper[label="3. TAN code\n+ address"];
+ helper->messenger[label="4. TAN code\n+ address"];
+ messenger->user[label="5. TAN code"];
+ user->challenger[label="6. TAN\ncode"];
+ user->exchange[label="7. Token"];
+ exchange->challenger[label="8. Get\nvalidated\naddress"];
+}
diff --git a/coin.dot b/images/coin.dot
index 3112a1b6..3112a1b6 100644
--- a/coin.dot
+++ b/images/coin.dot
diff --git a/deposit.dot b/images/deposit.dot
index 49bbf6df..49bbf6df 100644
--- a/deposit.dot
+++ b/images/deposit.dot
diff --git a/diagram.dot b/images/diagram.dot
index 1ddc6d2b..1ddc6d2b 100644
--- a/diagram.dot
+++ b/images/diagram.dot
diff --git a/images/exchange-db.png b/images/exchange-db.png
new file mode 100644
index 00000000..7a4050c6
--- /dev/null
+++ b/images/exchange-db.png
Binary files differ
diff --git a/images/grafana-postgres-exporter.png b/images/grafana-postgres-exporter.png
new file mode 100644
index 00000000..a51c28f0
--- /dev/null
+++ b/images/grafana-postgres-exporter.png
Binary files differ
diff --git a/images/kuma.png b/images/kuma.png
new file mode 100644
index 00000000..d98772a1
--- /dev/null
+++ b/images/kuma.png
Binary files differ
diff --git a/images/kyc-process.pdf b/images/kyc-process.pdf
new file mode 100644
index 00000000..8b178c02
--- /dev/null
+++ b/images/kyc-process.pdf
Binary files differ
diff --git a/images/kyc-process.png b/images/kyc-process.png
new file mode 100644
index 00000000..563418b1
--- /dev/null
+++ b/images/kyc-process.png
Binary files differ
diff --git a/images/kyc-process.tex b/images/kyc-process.tex
new file mode 100644
index 00000000..c10dd8d9
--- /dev/null
+++ b/images/kyc-process.tex
@@ -0,0 +1,58 @@
+\documentclass[fleqn]{article}
+\usepackage{amsmath}
+\usepackage{multimedia}
+\usepackage[utf8]{inputenc}
+\usepackage{framed,color,ragged2e}
+\usepackage[absolute,overlay]{textpos}
+\usepackage{xcolor}
+\usepackage{relsize}
+\usepackage{graphicx}
+\usepackage{tikz,eurosym,calc}
+\usetikzlibrary{tikzmark}
+\usetikzlibrary{shapes,arrows,arrows.meta}
+\usetikzlibrary{positioning,fit,patterns}
+\usetikzlibrary{calc}
+\usepackage{pgf-umlsd}
+\usepackage{relsize}
+
+\pagestyle{empty}
+\begin{document}
+
+\begin{sequencediagram}
+ \newinst{customer}{Customer}
+ \newinst[4]{ex}{Exchange}
+ \newinst[4]{kyc}{KYC Provider}
+ \postlevel
+ \mess[0]{customer}{POST: payment request}{ex}
+ \mess[0]{ex}{POST: initiate KYC}{kyc}
+ \mess[0]{kyc}{KYC-Start-URL}{ex}
+ \mess[0]{ex}{KYC-Start-URL}{customer}
+ \postlevel
+ \mess[0]{customer}{GET: KYC-Start-URL}{kyc}
+ \mess[0]{kyc}{KYC Web Form}{customer}
+ \mess[0]{customer}{POST: KYC data}{kyc}
+ \mess[0]{kyc}{redirect URL or pending}{customer}
+ \postlevel
+ \begin{sdblock}{alternative}{}
+ \mess[0]{customer}{GET: redirect URL}{ex}
+ \mess[0]{ex}{Thanks!}{customer}
+ \end{sdblock}
+ \prelevel
+ \prelevel
+ \prelevel
+ \prelevel
+ \prelevel
+ \begin{sdblock}{alternative}{}
+ \mess[0]{kyc}{Async validation finished Webhook}{ex}
+ \mess[0]{ex}{Thanks!}{kyc}
+ \end{sdblock}
+ \postlevel
+ \mess[0]{ex}{GET: KYC status?}{kyc}
+ \mess[0]{kyc}{KYC data}{ex}
+ \mess[0]{customer}{POST: payment request}{ex}
+ \mess[0]{ex}{normal response}{customer}
+\end{sequencediagram}
+
+\end{document}
+
+
diff --git a/merchant-db.png b/images/merchant-db.png
index ef7e1d05..ef7e1d05 100644
--- a/merchant-db.png
+++ b/images/merchant-db.png
Binary files differ
diff --git a/images/regional-arch.dot b/images/regional-arch.dot
new file mode 100644
index 00000000..8a61ed5e
--- /dev/null
+++ b/images/regional-arch.dot
@@ -0,0 +1,36 @@
+digraph G {
+ subgraph cluster_2 {
+ ubank;
+ nexus;
+ rank="same"; ebank; mbank;
+ label="Fiat currency";
+ };
+ subgraph cluster_1 {
+ user;
+ exchange;
+ shop;
+ rbank;
+ label="Regional currency";
+ };
+ subgraph cluster_2b {
+ }
+ user[label="Customer (Wallet)"];
+ shop[label="Merchant (Backend)"];
+ exchange[label="Exchange"];
+ ubank[label="Customer Fiat Bank"];
+ ebank[label="Exchange Fiat Bank"];
+ mbank[label="Merchant Fiat Bank"];
+ rbank[label="Regional Currency Bank"];
+ user->ubank [label="1. Initiate withdraw"];
+ ubank->ebank [label="2. Wire transfer"];
+ ebank->nexus [label="3. EBICS (CAMT)"];
+ nexus->rbank [label="4. Conversion (Cash-in)"];
+ rbank->exchange [label="5. Wirewatch"];
+ exchange->user [label="6. Withdraw E-Cash"];
+ user->shop [label="7. Spend E-Cash"];
+ shop->exchange [label="8. Deposit E-Cash"];
+ exchange->rbank [label="9. Credit Shop"];
+ rbank->nexus [xlabel="10. Conversion (Cash-out)"];
+ nexus->ebank [label="11. EBICS (PAIN)"];
+ ebank->mbank [label="12. Wire-transfer"];
+}
diff --git a/images/regional-arch.png b/images/regional-arch.png
new file mode 100644
index 00000000..a3691aea
--- /dev/null
+++ b/images/regional-arch.png
Binary files differ
diff --git a/images/regional-currency-architecture-diagram.png b/images/regional-currency-architecture-diagram.png
new file mode 100644
index 00000000..e55c5b68
--- /dev/null
+++ b/images/regional-currency-architecture-diagram.png
Binary files differ
diff --git a/replication.png b/images/replication.png
index 855237fc..855237fc 100644
--- a/replication.png
+++ b/images/replication.png
Binary files differ
diff --git a/replication.svg b/images/replication.svg
index 4a9eff34..4a9eff34 100644
--- a/replication.svg
+++ b/images/replication.svg
diff --git a/reserve.dot b/images/reserve.dot
index af6e3e86..af6e3e86 100644
--- a/reserve.dot
+++ b/images/reserve.dot
diff --git a/images/taler-logo.svg b/images/taler-logo.svg
new file mode 100644
index 00000000..dc4f5bcb
--- /dev/null
+++ b/images/taler-logo.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" width="300" height="100" viewBox="0 0 200 100"><g fill="#0042b3" fill-rule="evenodd" stroke-width=".3"><path d="M86.7 1.1c15.6 0 29 9.4 36 23.2h-5.9A35.1 35.1 0 0086.7 6.5C67 6.5 51 23.6 51 44.7c0 10.4 3.8 19.7 10 26.6a31.4 31.4 0 01-4.2 3A45.2 45.2 0 0146 44.7c0-24 18.2-43.6 40.7-43.6zm35.8 64.3a40.4 40.4 0 01-39 22.8c3-1.5 6-3.5 8.6-5.7a35.6 35.6 0 0024.6-17.1z"/><path d="M64.2 1.1l3.1.1c-3 1.6-5.9 3.5-8.5 5.8a37.5 37.5 0 00-30.2 37.7c0 14.3 7.3 26.7 18 33.3a29.6 29.6 0 01-8.5.2c-9-8-14.6-20-14.6-33.5 0-24 18.2-43.6 40.7-43.6zm5.4 81.4a35.6 35.6 0 0024.6-17.1h5.9a40.4 40.4 0 01-39 22.8c3-1.5 5.9-3.5 8.5-5.7zm24.8-58.2a37 37 0 00-12.6-12.8 29.6 29.6 0 018.5-.2c4 3.6 7.4 8 9.9 13z"/><path d="M41.8 1.1c1 0 2 0 3.1.2-3 1.5-5.9 3.4-8.5 5.6A37.5 37.5 0 006.1 44.7c0 21.1 16 38.3 35.7 38.3 12.6 0 23.6-7 30-17.6h5.8a40.4 40.4 0 01-35.8 23C19.3 88.4 1 68.8 1 44.7c0-24 18.2-43.6 40.7-43.6zm30.1 23.2a38.1 38.1 0 00-4.5-6.1c1.3-1.2 2.7-2.2 4.3-3 2.3 2.7 4.4 5.8 6 9.1z"/></g><path d="M76.1 34.4h9.2v-5H61.9v5H71v26h5.1zM92.6 52.9h13.7l3 7.4h5.3l-12.7-31.2h-4.7L84.5 60.3h5.2zm11.8-4.9h-9.9l5-12.4zM123.8 29.4h-4.6v31h20.6v-5h-16zM166.5 29.4H145v31h21.6v-5H150v-8.3h14.5v-4.9h-14.5v-8h16.4zM191.2 39.5c0 1.6-.5 2.8-1.6 3.8s-2.6 1.4-4.4 1.4h-7.4V34.3h7.4c1.9 0 3.4.4 4.4 1.3 1 .9 1.6 2.2 1.6 3.9zm6 20.8l-7.7-11.7c1-.3 1.9-.7 2.7-1.3a8.8 8.8 0 003.6-4.6c.4-1 .5-2.2.5-3.5 0-1.5-.2-2.9-.7-4.1a8.4 8.4 0 00-2.1-3.1c-1-.8-2-1.5-3.4-2-1.3-.4-2.8-.6-4.5-.6h-12.9v31h5V49.4h6.5l7 10.8z"/></svg>
diff --git a/images/taler-monitoring-infrastructure.png b/images/taler-monitoring-infrastructure.png
new file mode 100644
index 00000000..05f29704
--- /dev/null
+++ b/images/taler-monitoring-infrastructure.png
Binary files differ
diff --git a/images/transaction-common-states.dot b/images/transaction-common-states.dot
new file mode 100644
index 00000000..a3597f80
--- /dev/null
+++ b/images/transaction-common-states.dot
@@ -0,0 +1,52 @@
+digraph G {
+
+ initial[label="", shape="circle"];
+ pending[label="pending"];
+ dialog[label="dialog", shape="box"];
+ done[label="done", shape="box"];
+ aborted[label="aborted", shape="box", style="dashed"];
+ aborting[label="aborting", style="dashed"];
+ expired[label="expired", shape="box"];
+ failed[label="failed", shape="box"];
+ suspended[label="suspended", shape="box"];
+ suspended_aborting[label="suspended-aborting", shape="box", style="dashed"];
+ deleted[label="deleted", shape="box"];
+
+ subgraph {
+ rank = same; done; failed; expired; aborted;
+ }
+ subgraph {
+ rank = same; pending; aborting;
+ }
+ subgraph {
+ rank = same; dialog; suspended; suspended_aborting;
+ }
+
+ initial->pending;
+ pending->suspended [color="blue",label="suspend"];
+ pending->expired [label="expire"];
+ pending->dialog [color="green",label="success"];
+ pending->pending [color="green",label="progress"];
+ pending->done [color="green",label="success"];
+ pending->failed [color="red",label="failure"];
+ pending->failed [color="blue",label="fail"];
+ pending->aborting [color="blue",label="abort", style="dashed"];
+ dialog->pending [color="blue",label="OK"];
+ dialog->deleted [color="blue", label="delete"];
+ dialog->expired [label="expire"];
+ dialog->aborting [color="blue", label="refuse", style="dashed"];
+ suspended->pending [color="blue",label="resume"];
+ suspended->aborting [color="blue",label="abort", style="dashed"];
+ suspended->expired [label="expire"];
+ aborting->aborting [color="green",label="progress"];
+ aborting->aborted [color="green",label="success"];
+ aborting->suspended_aborting [color="blue",label="suspend"];
+ aborting->failed [color="red",label="failure"];
+ aborting->failed [color="blue",label="fail"];
+ suspended_aborting->aborting [color="blue",label="resume"];
+ suspended_aborting->failed [color="blue",label="fail"];
+ failed->deleted [color="blue",label="delete"];
+ expired->deleted [color="blue",label="delete"];
+ aborted->deleted [color="blue",label="delete"];
+ done->deleted [color="blue",label="delete"];
+}
diff --git a/images/transaction-common-states.svg b/images/transaction-common-states.svg
new file mode 100644
index 00000000..a5249eb7
--- /dev/null
+++ b/images/transaction-common-states.svg
@@ -0,0 +1,16 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 551.0166702270508 470" width="551.0166702270508" height="470">
+ <!-- svg-source:excalidraw -->
+ <!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1dXVPbSlx1MDAxMn3Pr6C4r7HuTM/3fSNcdTAwMDHzXHUwMDE1IFx1MDAxMMdcdTAwMTC2tm45tlxmwsJ2bDlAbuW/b49cdTAwMDFLlixh2bJcdTAwMTG7K1dcdTAwMDWQZE1L6nPmdPfM5J93XHUwMDFiXHUwMDFim8FD3938a2PTvW82fK81aNxtvrf7f7qDodfr4iFcdTAwMTj/PeyNXHUwMDA2zfGZ10HQXHUwMDFm/vXnn+E3nGbv9vFbru/eut1giOf9XHUwMDBi/97Y+Gf8b7RcdTAwMWTf9/pDd3z6+ECkIcLie4973XGjklx1MDAxMcaVXHUwMDEwZHKCN9zGxlx1MDAwMreFR9tccn/ohkfsrs3Dmlx1MDAxZlx1MDAxOHn18/iXW/Ol73Xae6pcdTAwMTe22vZ8/0vw4D/eUaN5PVx1MDAxYURsXHUwMDFhXHUwMDA2g17HPfdawTVcdTAwMWWnsf2T71xye3j/4bdcdTAwMDa90dV111x1MDAxZNq7XHUwMDBmXHLt9Vx1MDAxYk0veLDXIeHeRvdqfI1wzz3+VdHCXHUwMDAxMdllv1RRjoi1/7Hn91x1MDAwNrb9P8h4XHUwMDBiLfjeaHau0Ixua3JOMGh0h/3GXHUwMDAw30p43t3TnUHY/LXrXV1cdTAwMDfT+4bu+PEqXHUwMDAzVFx1MDAwMFx1MDAwM5hcdTAwMWOwbfT3W+PX/O/o/XdbT/ffXHUwMDFk+X5olj2wXHUwMDEzd42oe0Re3GB4eulcdTAwMDJcdTAwMWN+uzlcdTAwMGVutlx1MDAwZW4u2dHoeGL6lC81XHUwMDA2g97d5uTI76ffQotG/Vbj0UWo1PZRaWaI4pPjvtftxI31e81O6FXjvb/fz/blwL1cdTAwMGZmOXKkhZhcdTAwMWZTXHUwMDEwmlBOuZzbkZX6dNA/q/bL7ruMJ1xcl8qVea6iXHUwMDBlZbhRMFqDpjDDkVnckSlnwlx1MDAwMFxiWXpPfp913ZODz9Uz9/JHcH65W6tcdTAwMWV/van2g89cdTAwMDVcXPdcXPZcdTAwMGY++e27mrd3rPbO2lx1MDAwN3dcdTAwMWbd81x1MDAwMq47+kXcTmX7S/2m/9BcdTAwMWHd3Fx1MDAxZtZujltcdTAwMDVcXPdbN6h//vt2UK/UmsPLykdV+/u7LOC6ny+q9+zIPTy4MJ9cdTAwMGV2L7fPPpPOnPa+yECUMiGMysFAIex73eCL98ud5mi7t9q49fyH56760UBLTWhg3+22vO7V5tSBLd+7sjy16bvtaVx1MDAwMlx1MDAwYjzs0yeHg16EdZrYUMPruoP9Vtzg3sC78rpccr+W1ijepbv3jEtErliIVqkh8b3PvCpAXHUwMDEz0GDm11x1MDAwN1Whj/Z3brdKT6vAXHUwMDFktUZeXHUwMDA1R2rkVWRKXCK0MGFPlsGrUoJcdTAwMDKjWGj5KmlcdTAwMTXa/nl198pcZjv9+n7/28np913+UFx1MDAwNJ1cXHbYz52DXHUwMDFi70LfNlv1tqLt+odcdTAwMDKu2z06v6n6X1x1MDAxZuTJ1cn97Wjrm9c8uStM0KDPXHUwMDBiiFx1MDAwMm2ldNL43kOOWDefJFstiFBYqlCTklx1MDAxMmDamLlcdOVnh/Ba8+ao7ITCrU4zxFx1MDAxMCm4wi18XHUwMDA0Y25cdTAwMDGqXHUwMDFkboBPPquLPtBcdTAwMTIucVNUXHQwXHUwMDEw6Vx1MDAxNbM0nGTKWmXWQzZLaKKXtVx1MDAwMNNS6PVpgVav66ZcdTAwMDC3ic/CXHUwMDFkrFx1MDAwMLrTbVx1MDAxNlx1MDAwNNtIJFx1MDAxYddcdTAwMDGcXHUwMDExzpVcYlx1MDAxZupLsL0//XZyxqBadtgyalx1MDAxYzJGpFx1MDAxMpRcYlx1MDAxMkqAJ9hcdTAwMWFH08iHxywrXHUwMDBltlI7xMJWSG4wko1Yklx1MDAxOXpJSqmKxL2rRO2quvJdUv377qwx7JGL6k1/+4L6nY9zRlx1MDAxY3OwgVx1MDAwMVxuNIqV1XflbutcdTAwMTV68mijXHUwMDA1MYJIZVx1MDAwNHQ8boxcdTAwMTJ5KOFB77Yvd05LT1x0jDh4llx1MDAxMppjP1wimFxmUTd+5UQ4wmg++aiYZVx1MDAwNfbkypFcdTAwMTQpgWstOYI8fFx1MDAwNlx1MDAxOZRgpDRoXHUwMDFmXU9HvoRcbs+khCWSXHUwMDFi81CCijL9qimh3fD8dTNCvM2CXGJB6TRCYMCYYkLNnypcdTAwMTBHXHUwMDBmvzqdw72y80FF6Xhcblx1MDAxNlxiW2H5wCjUXHUwMDFjuZWA4EZcdTAwMTOMPdaD+1UlXHSXSMK+jHtcZutBrFx1MDAwZvfD0dCm7NZccv1cdTAwMTnN5kP/44OdXHUwMDAxf1x1MDAxNumBXHUwMDEyeoApZFWWI1WYnccvK1x1MDAxOVxi5Vx1MDAwMIbWxEhhKGXAp5mBOopayUC5oYajSNIx04qjXHSNOoRGLFx0XHK5XHUwMDBlX7U2VFxirqlhoCRE4oTnXHUwMDFjI1K2zUvmKd2EsH12XHUwMDE5eNrzO7yZOJm8VD1cXFxilsOgMVxiPniPafEpw54q5vtzXHUwMDE0rcdAbo6slVx1MDAxNeJcdTAwMTCmUG0xTlxykVx1MDAwNt9cdTAwMWbhkfOuXHUwMDFhffvgXHUwMDEzd4twe9mKRMVxumF8P0RzKiRcdTAwMThcdTAwMDKCMZFoVyba9Vx1MDAxYsPgY+/21lx1MDAwYvCBfu553SD+4MZPaMtcdTAwMDL62m0kqFx1MDAwM+2OXHUwMDFliyO/b6843Vx1MDAxNYS/bYTIXHUwMDE4/zH5/d/vZ56d6q52qyQ9Nbzeu+jP3KTFIyFKjLQ0QpVLkmP4Q3b3VFLOYtJcdTAwMDHG8SORo40yMcYyjiCRjcXsXG5cdItJ3m6qJYogyuFcYniMnShobtSMxCRVzCEp1jzpXHUwMDFjRfDrTNEwXHUwMDEzs3bGelx1MDAxNFx1MDAxMiGzXHUwMDE3z1hZXFxBXHUwMDFjIa0uXHUwMDE0glFccpRAkqEoTL9TWJCyXHUwMDEyXHUwMDEyfZqyOGVIl8RcdTAwMTImxqeKqqQhxDHRTSWf+1visEqqXHUwMDBi2y3pvEVxXHUwMDE4Yya+d1wivITFtWYk7MFfXCKx7OR7SUlMXHUwMDFhh2OIKVx1MDAxMP1KcKBhy4+JWplcdTAwMTGQwXfdYO7ixEVcdTAwMWQpXHUwMDE4XHUwMDE4QzEgo0JcdTAwMTk2S2pJXHUwMDFhteCRrIQ2QKSORM2vwFWor8RC1ZBcdTAwMDK4ylxuKkW01Fx1MDAxY7RNS1x1MDAxMa6SusYsRk6JyuBcdTAwMTRHcoIvXG7lXHUwMDA25dxcdTAwMDBcdTAwMDYmbI5m31x1MDAxMlx1MDAxNaX7pN0qY3csin5cdTAwMDSk0lx1MDAwZmjL6pFq50vkkz3MoKTkXHUwMDAzwFx1MDAxY1tcdTAwMWVixqZkpFx1MDAwZXu6R/bR0pFcdTAwMDS7QDtqQKDKTa9cdTAwMTItq6GMQC2HJlx1MDAxMDuQXHUwMDA0+/9QXHUwMDFmTZhIXHUwMDEzh0lDOeJcdTAwMWb7XHUwMDA2Jlx1MDAxMqyE94skytlrslx1MDAxMpXIS6tUUPVu9ZDI81x1MDAxZtv76sc17Xzyd47q1dlUgeJcdTAwMTgwYLdcdTAwMTl/w8Ihj6GIcfAotyNxUHVyXGZcdTAwMGJcdTAwMTckrMTYqGmi1ETawIfbcUJcdTAwMDbjpP+y+C/Vc+2W8NnClFPGoGEmOD5xkYO8slx1MDAwYqAlJS98mo6RiDhU6YpFXHUwMDFj/Ek58Vx1MDAxNSonjFWUklx1MDAxMiR2VkxcdFAzXHUwMDA2vlGpksrJclx1MDAxNGo9xV41zKOg5CqlU1x1MDAxNiOgclx1MDAxMlx1MDAxOFlZalx1MDAxMohccpDh8MRIeLVcdTAwMThcdTAwMTMlRmdMM1x1MDAxMTBCXHUwMDA016izXHUwMDE115olmUgkmn1LTJTulHarjP2xKP7hPJV/gKAgRlx1MDAwN+fzR27Z1dbS8o9yiFx1MDAxNoRqQOKXepp/qMign6aBXHUwMDA2NJZcbtxcdTAwMTSG4ZJTovBfmDXuXHUwMDE2e6JcdTAwMTdSTopcdTAwMTnDXHUwMDE4vGbGiVx1MDAxOHyAsNCA1Fx1MDAwMqjIRnFcdTAwMTjCoThcdTAwMTLPP1x1MDAxM5SgXHUwMDE2ZKL4oJBYs0A40VQyQKxcdTAwMTI5Q5wl231LVFRJ91C7JX0zJy+lXHUwMDE18llqXHUwMDFkXHUwMDFmMWpcdTAwMTRcdTAwMTBlwjNeYqX9o2NNq3VZdlwiqsjkVCquV6h+XHUwMDE0YNSIolx1MDAwYpGriCCRNFBWIZ9xY+zAozx0k13Iz+JcdTAwMTWBnre+0XHDUbNpLZ46sPqCeKzRgsrhXHUwMDE51XBGbbCo1Pwgylx1MDAxZfBUUkRhUFx1MDAxMZ9FQ7NcdTAwMTKxy/bnyEuzOnBcdTAwMWHHXHUwMDEwYJCJ/i1JnnGxhZe1XHUwMDE1ZZG5O2tPvHKMbMFWZ4jk3PYuM8JcdTAwMDcnqeSL6LaxWa1cdTAwMThRlluAq2SvnaxHvaVeO+KGdkNcdTAwMDfM2S2nUkq0qlx1MDAxOOeUceJEyVx1MDAxY4We7EFaJeVcdTAwMTTiaIVhN+XScMa45tND8qmhXHUwMDE5XHUwMDA0s3SJXHUwMDFhL66ZUiiBJD5sXHUwMDFh5r0jJepEsoJhLGlcZuSaqLeSkvQqc1x1MDAxNVm1YJu901x1MDAwNqid26g5YURHTnouSS/GNC+NmpFcdTAwMDI4YkLbMVlCJds1MyjuLXFNqkfarYLOWFx1MDAxOPXI1Fwij1x1MDAxMFx1MDAwMEbLXHUwMDFjY/uyZ3SUlHlslUdcdTAwMWImKfJcdTAwMGY3XHUwMDE4csdqzFx1MDAwNlx1MDAxY2LHOTKmhVx1MDAxMkrFLSuwylx1MDAwM46RXHUwMDFjga1tdipqSEhDhDlcdTAwMDbDcZSaWqPaNIlAgqOVyphXzaBS7LDUQuFF8WVcdTAwMWWq8c1qfIFcdTAwMWGQrMNcdTAwMDFcdTAwMDRcdTAwMWKROlx1MDAwZkNzQVEuJCCtLJrTyMiuXHUwMDEyR4JcdTAwMDE7P1x1MDAxMewgXHUwMDFljPRcdTAwMTJmvG2+SnVdu1WSXpuTvtJcdTAwMTJcdTAwMWE8dZBcdTAwMWZcdTAwMTWIV06pnl83XdWPto9/9Mtf2ZEmmdFg6bT0OvlcZsSTwEiswIlcdJklXHUwMDFiqWlow//zXHUwMDE580NcYtLTXHUwMDE5XHUwMDA0qFx1MDAwMaVzVEpV8GVvu9ZVZYdcdTAwMTB2XG6JXGZcdTAwMDZkTe5ZNoXBUUTYkZCaY3SMinm+pUBcdTAwMDCVtbRZ4jxjNlx1MDAxNlx1MDAwN5GQdLG650IgcrE7XHUwMDFhrFx1MDAxN0KxJotcdTAwMDFQZGpRXHUwMDFjQFx1MDAxOJ5cdEaRO+dcdTAwMDZQcHt4cVU/KH1cbpDJRFadRlJcdTAwMTTlgI/VfShGo/W/VcJcdTAwMDfjUbNQ4u9/XHUwMDFhPip9srlGKUm5yVEpr41u+6SmS1x1MDAxZnNWdELCqaylKZdOcFx0m05gXGZcdTAwMDNcdTAwMTBpZ6fNt1x1MDAxMFx1MDAxNbq1XHUwMDE0dE2dj7ZyfY1cbm48W3LdXG4u1mhRXHUwMDBiL6VDiDG7Mlx1MDAxMaXz53A+NVx1MDAxYkc3Nz/cskOI0ziCTPqSXGbL4lx1MDAwN3s7bos7VFx1MDAwMEJIz8hcdTAwMGbP6H2sT+O3cmViXHUwMDE2x48h0Vx1MDAxOHDV+Fx1MDAxObjD0W3a+kcrgk+8zWLQk5VC4EJKO8tpbvA0XHUwMDBmt7buTlx1MDAwZptlXHUwMDA3XHUwMDBmRueJdVx1MDAxMFfaXHUwMDAxcenQ3GuaIII4Z1x1MDAxMtYyJmKsXHUwMDEz+UJj01x1MDAxN18xaL1cdTAwMDCKNZlcdTAwMGY/XHUwMDE5S41Tlo4hyqStR8P8XHUwMDFhLju3W1JA2YX+XHUwMDA0UWLy0dPgMtSJLlx1MDAxZZSxPsCySJsxSS05QY1cbju6cU2LhiyxXHUwMDAy8Pus6y6xfljmdZdYXHUwMDEy9em3l0ojeaLETFCmlvUoSc1KcIlqXHUwMDAxIEdWL/tcdTAwMDWWXHUwMDE0kXaQkl1FXHUwMDA3mMRcdTAwMGbocGbNU8bcOFx1MDAwMrgxlFx0gzEmWVx1MDAxZFwiKUGpaiRwO217rMaTXHUwMDEwRYGppWKCXHUwMDFhQeya1nHEXHUwMDFhrVx1MDAwNO7P1Vx1MDAxM1x1MDAxNj95XHUwMDBiXGLNs9x/5IlcdTAwMTYw/Z0zfIhcdTAwMDJfhsB/lE7OOjeONpH3rVx1MDAxN6zjzV1btONcdTAwMTDQXHUwMDE4XHUwMDE0+FQrXHUwMDA26EKQXHUwMDFjIFxyXHUwMDBl2GVcdTAwMGI0szP2QUjCXHUwMDEzVr2lOl+6L9utXHUwMDEyd+Pwcu+iP9PobOA2g0c0z6A0kfr/maD+YHZcdTAwMTmVSCnjJUrbue9cdTAwMWXsfVx1MDAxNec7XHUwMDFm6rXTk3PYv+Q7O2WnNKZcdTAwMWNcdTAwMDahxFx1MDAxMDKx2rBx7FrEk08qpS27XGKR0Fx1MDAwZYtudFZCSTg6elx1MDAwZU+WNzBqxVxiXHUwMDE5oLh1TLPXXHUwMDA3ppFcdTAwMTWol+x5M11cdTAwMTVS9bDSRFGQeSb//GrtfjK3RPDL092ds/bXi7r0Su+plDo64qrx9XWBrGt9XVxyzlxmRVxmXHRJjLGpIdi/rSXZSbUxkGfpq8VdkaVXp7Cn1DarlSO97lx1MDAxZvUuf2xVR2bv9Pvp/nH9uNl7XHUwMDAzvpi6XHUwMDA2+/PCroSK8LPC/1x1MDAwZYJMM+KsJdq5Y9Mkk21GTYvZlFS+xUVcdTAwMTZ3VMNcdTAwMTTkj1bePemHzUa//yXAS07k1uZPz737kHxuf7THm1xypcZubn3JXHUwMDFki9jf737/XHUwMDA3Yp+BqSJ9<!-- payload-end -->
+ <defs>
+ <style class="style-fonts">
+ @font-face {
+ font-family: "Virgil";
+ src: url("https://excalidraw.com/Virgil.woff2");
+ }
+ @font-face {
+ font-family: "Cascadia";
+ src: url("https://excalidraw.com/Cascadia.woff2");
+ }
+ </style>
+ </defs>
+ <rect x="0" y="0" width="551.0166702270508" height="470" fill="#ffffff"></rect><g stroke-linecap="round" transform="translate(14 223.31818181818184) rotate(0 10 10)"><path d="M20 10 C20 10.58, 19.95 11.17, 19.85 11.74 C19.75 12.31, 19.59 12.88, 19.4 13.42 C19.2 13.96, 18.95 14.5, 18.66 15 C18.37 15.5, 18.03 15.98, 17.66 16.43 C17.29 16.87, 16.87 17.29, 16.43 17.66 C15.98 18.03, 15.5 18.37, 15 18.66 C14.5 18.95, 13.96 19.2, 13.42 19.4 C12.88 19.59, 12.31 19.75, 11.74 19.85 C11.17 19.95, 10.58 20, 10 20 C9.42 20, 8.83 19.95, 8.26 19.85 C7.69 19.75, 7.12 19.59, 6.58 19.4 C6.04 19.2, 5.5 18.95, 5 18.66 C4.5 18.37, 4.02 18.03, 3.57 17.66 C3.13 17.29, 2.71 16.87, 2.34 16.43 C1.97 15.98, 1.63 15.5, 1.34 15 C1.05 14.5, 0.8 13.96, 0.6 13.42 C0.41 12.88, 0.25 12.31, 0.15 11.74 C0.05 11.17, 0 10.58, 0 10 C0 9.42, 0.05 8.83, 0.15 8.26 C0.25 7.69, 0.41 7.12, 0.6 6.58 C0.8 6.04, 1.05 5.5, 1.34 5 C1.63 4.5, 1.97 4.02, 2.34 3.57 C2.71 3.13, 3.13 2.71, 3.57 2.34 C4.02 1.97, 4.5 1.63, 5 1.34 C5.5 1.05, 6.04 0.8, 6.58 0.6 C7.12 0.41, 7.69 0.25, 8.26 0.15 C8.83 0.05, 9.42 0, 10 0 C10.58 0, 11.17 0.05, 11.74 0.15 C12.31 0.25, 12.88 0.41, 13.42 0.6 C13.96 0.8, 14.5 1.05, 15 1.34 C15.5 1.63, 15.98 1.97, 16.43 2.34 C16.87 2.71, 17.29 3.13, 17.66 3.57 C18.03 4.02, 18.37 4.5, 18.66 5 C18.95 5.5, 19.2 6.04, 19.4 6.58 C19.59 7.12, 19.75 7.69, 19.85 8.26 C19.95 8.83, 19.97 9.71, 20 10 C20.03 10.29, 20.03 9.71, 20 10" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(133.5 214.81818181818184) rotate(0 35.56666564941406 11.5)"><text x="0" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">pending</text></g><g transform="translate(424 214.81818181818184) rotate(0 36.34166717529297 11.5)"><text x="0" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">aborting</text></g><g transform="translate(143.50909065477774 12.325757575757592) rotate(0 22.233333587646484 11.5)"><text x="22.233333587646484" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">done</text></g><g transform="translate(418.2924247510506 11) rotate(0 34.03333282470703 11.5)"><text x="0" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">aborted</text></g><g transform="translate(429.35075846585363 436.41666666666674) rotate(0 23.808332443237305 11.5)"><text x="0" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">failed</text></g><g transform="translate(21 434.31818181818187) rotate(0 48.90833282470703 11.5)"><text x="0" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">suspended</text></g><g stroke-linecap="round"><g transform="translate(41.982890340886755 232.53354496737632) rotate(0 42.75855482955662 -0.9457774096638123)"><path d="M0 0 C14.25 -0.32, 71.26 -1.58, 85.52 -1.89 M0 0 C14.25 -0.32, 71.26 -1.58, 85.52 -1.89" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(41.982890340886755 232.53354496737632) rotate(0 42.75855482955662 -0.9457774096638123)"><path d="M57.56 8.99 C68.59 4.7, 79.63 0.4, 85.52 -1.89 M57.56 8.99 C67.72 5.04, 77.87 1.08, 85.52 -1.89" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(41.982890340886755 232.53354496737632) rotate(0 42.75855482955662 -0.9457774096638123)"><path d="M57.11 -11.53 C68.32 -7.72, 79.53 -3.92, 85.52 -1.89 M57.11 -11.53 C67.43 -8.03, 77.75 -4.53, 85.52 -1.89" stroke="#000000" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(135.48434363799794 250.31818181818187) rotate(0 -38.740049206424885 86.50000000000001)"><path d="M0 0 C-12.91 28.83, -64.57 144.17, -77.48 173 M0 0 C-12.91 28.83, -64.57 144.17, -77.48 173" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(135.48434363799794 250.31818181818187) rotate(0 -38.740049206424885 86.50000000000001)"><path d="M-75.32 143.08 C-75.83 150.16, -76.34 157.25, -77.48 173 M-75.32 143.08 C-75.84 150.23, -76.35 157.38, -77.48 173" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(135.48434363799794 250.31818181818187) rotate(0 -38.740049206424885 86.50000000000001)"><path d="M-56.59 151.47 C-61.54 156.56, -66.48 161.66, -77.48 173 M-56.59 151.47 C-61.58 156.61, -66.58 161.76, -77.48 173" stroke="#364fc7" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(168.6733504175421 204.31818181818184) rotate(0 0.8266495824578968 -80.75)"><path d="M0 0 C0.28 -26.92, 1.38 -134.58, 1.65 -161.5 M0 0 C0.28 -26.92, 1.38 -134.58, 1.65 -161.5" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g><g transform="translate(168.6733504175421 204.31818181818184) rotate(0 0.8266495824578968 -80.75)"><path d="M11.62 -133.21 C9.32 -139.74, 7.02 -146.27, 1.65 -161.5 M11.62 -133.21 C8.28 -142.71, 4.93 -152.21, 1.65 -161.5" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g><g transform="translate(168.6733504175421 204.31818181818184) rotate(0 0.8266495824578968 -80.75)"><path d="M-8.9 -133.42 C-6.46 -139.9, -4.02 -146.38, 1.65 -161.5 M-8.9 -133.42 C-5.35 -142.85, -1.81 -152.28, 1.65 -161.5" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(322.76053964946817 144.21170891263012) rotate(0 47.619730175265914 40.184570842716774)"><path d="M0 0 C15.87 13.39, 79.37 66.97, 95.24 80.37 M0 0 C15.87 13.39, 79.37 66.97, 95.24 80.37" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(322.76053964946817 144.21170891263012) rotate(0 47.619730175265914 40.184570842716774)"><path d="M67.08 70.03 C73.71 72.46, 80.33 74.9, 95.24 80.37 M67.08 70.03 C74.85 72.88, 82.62 75.74, 95.24 80.37" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(322.76053964946817 144.21170891263012) rotate(0 47.619730175265914 40.184570842716774)"><path d="M80.31 54.35 C83.83 60.47, 87.34 66.6, 95.24 80.37 M80.31 54.35 C84.43 61.53, 88.55 68.71, 95.24 80.37" stroke="#364fc7" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(455.2111686673312 206.31818181818184) rotate(0 0.2888313326687637 -83.75)"><path d="M0 0 C0.1 -27.92, 0.48 -139.58, 0.58 -167.5 M0 0 C0.1 -27.92, 0.48 -139.58, 0.58 -167.5" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g><g transform="translate(455.2111686673312 206.31818181818184) rotate(0 0.2888313326687637 -83.75)"><path d="M10.74 -139.27 C8.32 -146.01, 5.89 -152.74, 0.58 -167.5 M10.74 -139.27 C8.28 -146.12, 5.81 -152.96, 0.58 -167.5" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g><g transform="translate(455.2111686673312 206.31818181818184) rotate(0 0.2888313326687637 -83.75)"><path d="M-9.78 -139.34 C-7.31 -146.06, -4.84 -152.78, 0.58 -167.5 M-9.78 -139.34 C-7.27 -146.17, -4.76 -152.99, 0.58 -167.5" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(456.3350182053682 246.31818181818184) rotate(0 -0.8350182053682147 91.50000000000001)"><path d="M0 0 C-0.28 30.5, -1.39 152.5, -1.67 183 M0 0 C-0.28 30.5, -1.39 152.5, -1.67 183" stroke="#c92a2a" stroke-width="1" fill="none"></path></g><g transform="translate(456.3350182053682 246.31818181818184) rotate(0 -0.8350182053682147 91.50000000000001)"><path d="M-11.67 154.72 C-9.33 161.34, -6.99 167.97, -1.67 183 M-11.67 154.72 C-8.06 164.93, -4.45 175.13, -1.67 183" stroke="#c92a2a" stroke-width="1" fill="none"></path></g><g transform="translate(456.3350182053682 246.31818181818184) rotate(0 -0.8350182053682147 91.50000000000001)"><path d="M8.85 154.9 C6.38 161.49, 3.92 168.07, -1.67 183 M8.85 154.9 C5.05 165.05, 1.25 175.19, -1.67 183" stroke="#c92a2a" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(93 82.31818181818184) rotate(0 36.25833511352539 11.5)"><text x="0" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#2b8a3e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">success</text></g><g stroke-linecap="round"><g transform="translate(216 247.31818181818184) rotate(0 103.5 90.5)"><path d="M0 0 C34.5 30.17, 172.5 150.83, 207 181 M0 0 C34.5 30.17, 172.5 150.83, 207 181" stroke="#c92a2a" stroke-width="1" fill="none"></path></g><g transform="translate(216 247.31818181818184) rotate(0 103.5 90.5)"><path d="M179.02 170.17 C189.65 174.28, 200.27 178.39, 207 181 M179.02 170.17 C188.5 173.84, 197.98 177.51, 207 181" stroke="#c92a2a" stroke-width="1" fill="none"></path></g><g transform="translate(216 247.31818181818184) rotate(0 103.5 90.5)"><path d="M192.53 154.72 C198.03 164.7, 203.52 174.68, 207 181 M192.53 154.72 C197.43 163.62, 202.34 172.53, 207 181" stroke="#c92a2a" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(100.12276146943348 422.31818181818187) rotate(0 35.791889863028594 -87.5)"><path d="M0 0 C11.93 -29.17, 59.65 -145.83, 71.58 -175 M0 0 C11.93 -29.17, 59.65 -145.83, 71.58 -175" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(100.12276146943348 422.31818181818187) rotate(0 35.791889863028594 -87.5)"><path d="M70.41 -145.02 C70.81 -155.4, 71.22 -165.77, 71.58 -175 M70.41 -145.02 C70.8 -155, 71.19 -164.97, 71.58 -175" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(100.12276146943348 422.31818181818187) rotate(0 35.791889863028594 -87.5)"><path d="M51.41 -152.79 C58.39 -160.48, 65.37 -168.16, 71.58 -175 M51.41 -152.79 C58.13 -160.18, 64.84 -167.57, 71.58 -175" stroke="#364fc7" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(323.14361727490984 138.80380843242415) rotate(0 46.482340426374904 -51.975306594086966)"><path d="M0 0 C15.49 -17.33, 77.47 -86.63, 92.96 -103.95 M0 0 C15.49 -17.33, 77.47 -86.63, 92.96 -103.95" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(323.14361727490984 138.80380843242415) rotate(0 46.482340426374904 -51.975306594086966)"><path d="M81.82 -76.1 C84.79 -83.51, 87.75 -90.92, 92.96 -103.95 M81.82 -76.1 C84.2 -82.04, 86.57 -87.98, 92.96 -103.95" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(323.14361727490984 138.80380843242415) rotate(0 46.482340426374904 -51.975306594086966)"><path d="M66.52 -89.78 C73.56 -93.55, 80.59 -97.32, 92.96 -103.95 M66.52 -89.78 C72.16 -92.8, 77.8 -95.82, 92.96 -103.95" stroke="#364fc7" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(468.5 99.81818181818184) rotate(0 36.25833511352539 11.5)"><text x="0" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#2b8a3e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">success</text></g><g transform="translate(286 354.31818181818187) rotate(0 21.049999237060547 11.5)"><text x="0" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#c92a2a" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">error</text></g><g transform="translate(465.5 332.81818181818187) rotate(0 21.049999237060547 11.5)"><text x="0" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#c92a2a" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">error</text></g><g transform="translate(10 308.31818181818187) rotate(0 37.79166793823242 11.5)"><text x="0" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#364fc7" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">suspend</text></g><g transform="translate(140.5 327.81818181818187) rotate(0 33.20000076293945 11.5)"><text x="0" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#364fc7" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">resume</text></g><g transform="translate(227 153.31818181818184) rotate(0 23.058332443237305 11.5)"><text x="0" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#364fc7" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">abort</text></g><g stroke-linecap="round" transform="translate(317.75757575757575 138.83333333333337) rotate(0 2.5 2.5)"><path d="M5 2.5 C5 2.64, 4.99 2.79, 4.96 2.93 C4.94 3.08, 4.9 3.22, 4.85 3.36 C4.8 3.49, 4.74 3.62, 4.67 3.75 C4.59 3.88, 4.51 4, 4.42 4.11 C4.32 4.22, 4.22 4.32, 4.11 4.42 C4 4.51, 3.88 4.59, 3.75 4.67 C3.62 4.74, 3.49 4.8, 3.36 4.85 C3.22 4.9, 3.08 4.94, 2.93 4.96 C2.79 4.99, 2.64 5, 2.5 5 C2.36 5, 2.21 4.99, 2.07 4.96 C1.92 4.94, 1.78 4.9, 1.64 4.85 C1.51 4.8, 1.38 4.74, 1.25 4.67 C1.12 4.59, 1 4.51, 0.89 4.42 C0.78 4.32, 0.68 4.22, 0.58 4.11 C0.49 4, 0.41 3.88, 0.33 3.75 C0.26 3.62, 0.2 3.49, 0.15 3.36 C0.1 3.22, 0.06 3.08, 0.04 2.93 C0.01 2.79, 0 2.64, 0 2.5 C0 2.36, 0.01 2.21, 0.04 2.07 C0.06 1.92, 0.1 1.78, 0.15 1.64 C0.2 1.51, 0.26 1.38, 0.33 1.25 C0.41 1.12, 0.49 1, 0.58 0.89 C0.68 0.78, 0.78 0.68, 0.89 0.58 C1 0.49, 1.12 0.41, 1.25 0.33 C1.38 0.26, 1.51 0.2, 1.64 0.15 C1.78 0.1, 1.92 0.06, 2.07 0.04 C2.21 0.01, 2.36 0, 2.5 0 C2.64 0, 2.79 0.01, 2.93 0.04 C3.08 0.06, 3.22 0.1, 3.36 0.15 C3.49 0.2, 3.62 0.26, 3.75 0.33 C3.88 0.41, 4 0.49, 4.11 0.58 C4.22 0.68, 4.32 0.78, 4.42 0.89 C4.51 1, 4.59 1.12, 4.67 1.25 C4.74 1.38, 4.8 1.51, 4.85 1.64 C4.9 1.78, 4.94 1.92, 4.96 2.07 C4.99 2.21, 4.99 2.43, 5 2.5 C5.01 2.57, 5.01 2.43, 5 2.5" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(215.3906236363281 211.29319045868777) rotate(0 50.64812410532706 -33.43367597517795)"><path d="M0 0 C16.88 -11.14, 84.41 -55.72, 101.3 -66.87 M0 0 C16.88 -11.14, 84.41 -55.72, 101.3 -66.87" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(215.3906236363281 211.29319045868777) rotate(0 50.64812410532706 -33.43367597517795)"><path d="M83.42 -42.77 C89.72 -51.26, 96.01 -59.75, 101.3 -66.87 M83.42 -42.77 C89.61 -51.12, 95.8 -59.46, 101.3 -66.87" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(215.3906236363281 211.29319045868777) rotate(0 50.64812410532706 -33.43367597517795)"><path d="M72.12 -59.9 C82.39 -62.35, 92.67 -64.81, 101.3 -66.87 M72.12 -59.9 C82.22 -62.31, 92.32 -64.72, 101.3 -66.87" stroke="#364fc7" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round" transform="translate(136.57575757575756 10.909090909090935) rotate(0 29.166666666666657 12.916666666666671)"><path d="M0 0 C18.84 0, 37.67 0, 58.33 0 M0 0 C22.09 0, 44.18 0, 58.33 0 M58.33 0 C58.33 8.9, 58.33 17.8, 58.33 25.83 M58.33 0 C58.33 6.77, 58.33 13.54, 58.33 25.83 M58.33 25.83 C39.95 25.83, 21.56 25.83, 0 25.83 M58.33 25.83 C40.09 25.83, 21.84 25.83, 0 25.83 M0 25.83 C0 16.47, 0 7.11, 0 0 M0 25.83 C0 17.29, 0 8.75, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(411.0757575757576 10) rotate(0 41.25 12.5)"><path d="M0 0 C26.08 0, 52.17 0, 82.5 0 M0 0 C29.89 0, 59.79 0, 82.5 0 M82.5 0 C82.5 9.92, 82.5 19.84, 82.5 25 M82.5 0 C82.5 7.27, 82.5 14.54, 82.5 25 M82.5 25 C65.79 25, 49.07 25, 0 25 M82.5 25 C51.76 25, 21.03 25, 0 25 M0 25 C0 16.54, 0 8.08, 0 0 M0 25 C0 19.95, 0 14.9, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(417.74242424242425 435.83333333333337) rotate(0 35.416666666666686 12.083333333333314)"><path d="M0 0 C23.12 0, 46.24 0, 70.83 0 M0 0 C26.44 0, 52.89 0, 70.83 0 M70.83 0 C70.83 8.75, 70.83 17.5, 70.83 24.17 M70.83 0 C70.83 4.89, 70.83 9.78, 70.83 24.17 M70.83 24.17 C44.44 24.17, 18.05 24.17, 0 24.17 M70.83 24.17 C54.46 24.17, 38.08 24.17, 0 24.17 M0 24.17 C0 15.54, 0 6.91, 0 0 M0 24.17 C0 16.22, 0 8.27, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g></svg> \ No newline at end of file
diff --git a/images/transaction-deposit-states.dot b/images/transaction-deposit-states.dot
new file mode 100644
index 00000000..fa8d91d8
--- /dev/null
+++ b/images/transaction-deposit-states.dot
@@ -0,0 +1,44 @@
+digraph G {
+
+ initial[label="", shape="circle", xlabel="deposit"];
+ pending_deposit[label="deposit"];
+ pending_track[label="track"];
+ pending_kyc[label="kyc"];
+ pending_aml[label="aml"];
+ aborting_refresh[label="refresh", style=dashed];
+ aborting_refund[label="refund", style=dashed];
+ done[label="done", shape="box"];
+ aborted[label="aborted", shape="box", style=dashed];
+
+ subgraph {
+ rank=same;
+ done; aborted;
+ }
+
+ subgraph {
+ rank=same;
+ pending_track; aborting_refund;
+ }
+
+ subgraph {
+ rank=same;
+ pending_deposit; pending_kyc; pending_aml;
+ }
+
+ initial->pending_deposit;
+
+ aborting_refund->aborting_refresh [color=green];
+ aborting_refresh->aborted [color=green];
+
+ pending_deposit->pending_track [color=green];
+ pending_deposit->aborting_refund [color="red"];
+ pending_deposit->aborting_refund [color="blue", style=dashed];
+
+ pending_track->aborting_refund [color="blue", style=dashed];
+ pending_track->done [color=green];
+ pending_track->pending_kyc [color=red];
+ pending_track->pending_aml [color=red];
+
+ pending_kyc->pending_track [color="green"];
+ pending_aml->pending_track [color="green"];
+}
diff --git a/images/transaction-payment-states.dot b/images/transaction-payment-states.dot
new file mode 100644
index 00000000..d0c602b5
--- /dev/null
+++ b/images/transaction-payment-states.dot
@@ -0,0 +1,48 @@
+digraph G {
+ initial[label="", shape="circle", xlabel="pay merchant"];
+ pending_dp[label="claim-proposal"];
+ pending_sp[label="submit-payment"];
+ pending_ar[label="auto-refund"];
+ pending_re[label="rebind-session"];
+ pending_cr[label="check-refund"];
+ pending_accept_refunds[label="accept-refund"];
+ aborting_pi[label="payment-incomplete", style=dashed];
+ aborted[label="aborted", shape="box", style=dashed];
+ dialog_proposal[label="dialog(merchant-order-proposed)", shape="box"];
+ done[label="done", shape="box"];
+
+ subgraph {
+ rank=same;
+ done; aborted; pending_re;
+ }
+
+ subgraph {
+ pending_ar; pending_sp;
+ }
+
+ initial -> pending_dp;
+
+ pending_dp -> dialog_proposal [color=green];
+
+ dialog_proposal -> pending_sp [color=blue];
+
+ pending_sp -> pending_ar [color=green];
+ pending_sp -> aborting_pi [color=blue,style=dashed];
+
+ aborting_pi->done [color=red];
+ aborting_pi->aborted [color=green];
+
+ pending_ar -> done [color=green, label="time over"];
+
+ pending_ar -> pending_accept_refunds;
+
+ done -> pending_cr [color=blue];
+ done -> pending_re [color=blue];
+
+ pending_cr -> done [color=green];
+ pending_cr -> pending_accept_refunds [color=green];
+
+ pending_accept_refunds -> done [color=green];
+
+ pending_re -> done [color=green];
+}
diff --git a/images/transaction-pull-credit-states.dot b/images/transaction-pull-credit-states.dot
new file mode 100644
index 00000000..bc979a30
--- /dev/null
+++ b/images/transaction-pull-credit-states.dot
@@ -0,0 +1,43 @@
+digraph G {
+ initial[label="", shape="circle"];
+ pending_create[label="purse-create"];
+ pending_qr[label="ready"];
+ aborting_delete[label="delete-purse", style=dashed];
+ pending_withdraw[label="withdraw"];
+ pending_kyc[label="kyc"];
+ pending_aml[label="aml"];
+
+ aborted[label="aborted", shape="box", style=dashed];
+ done[label="done", shape="box"];
+
+// subgraph {
+// rank = same; pending_withdraw; failed;
+// }
+
+ subgraph {
+ rank=max;
+ aborted; done;
+ }
+
+ subgraph {
+ rank=same;
+ pending_create; pending_qr;
+ }
+
+ initial->pending_create;
+
+ pending_create->pending_qr;
+
+ pending_qr->aborting_delete [color="blue", style=dashed];
+ pending_qr->pending_withdraw [color=green];
+
+ aborting_delete->pending_withdraw [color="red"];
+ aborting_delete->aborted [color=green];
+
+ pending_withdraw->done [color=green];
+ pending_withdraw->pending_kyc [color=red];
+ pending_withdraw->pending_aml [color=red];
+
+ pending_kyc->pending_withdraw [color="green"];
+ pending_aml->pending_withdraw [color="green"];
+}
diff --git a/images/transaction-pull-debit-states.dot b/images/transaction-pull-debit-states.dot
new file mode 100644
index 00000000..4a3d0dde
--- /dev/null
+++ b/images/transaction-pull-debit-states.dot
@@ -0,0 +1,34 @@
+digraph G {
+
+ initial[label="", shape="circle"];
+ pending_download[label="download"];
+ pending_user[label="monolog", shape="box"];
+
+ pending_deposit[label="deposit"];
+ aborting_refresh[label="refresh", style=dashed];
+
+ aborted[label="aborted", shape="box", style=dashed];
+ done[label="done", shape="box"];
+
+ subgraph {
+ rank=same;
+ done; aborted;
+ }
+
+ subgraph {
+ rank=same;
+ pending_download;
+ pending_user;
+ }
+
+ initial->pending_download;
+
+ pending_download->pending_user [color=green];
+
+ pending_user->pending_deposit [color="blue"];
+
+ pending_deposit->done [color=green];
+ pending_deposit->aborting_refresh [color=red];
+
+ aborting_refresh->aborted;
+}
diff --git a/images/transaction-push-credit-states.dot b/images/transaction-push-credit-states.dot
new file mode 100644
index 00000000..c51da308
--- /dev/null
+++ b/images/transaction-push-credit-states.dot
@@ -0,0 +1,37 @@
+digraph G {
+
+ initial[label="", shape="circle", xlabel="peer-push-credit"];
+ pending_download[label="pending(download)"];
+ pending_user[label="dialog", shape="box"];
+ pending_merge[label="merge"];
+ pending_merge_kyc[label="merge-kyc"];
+ pending_withdraw[label="withdraw"];
+ pending_withdraw_kyc[label="withdraw-kyc"];
+ pending_withdraw_aml[label="withdraw-aml"];
+
+ subgraph {
+ rank=same;
+ pending_merge; pending_withdraw_kyc; pending_withdraw_aml;
+ }
+
+ done[label="done", shape="box"];
+
+ initial->pending_download;
+
+ pending_download->pending_user [color=green];
+
+ pending_user->pending_merge [color="blue", label="OK"];
+
+ pending_merge->pending_withdraw [color=green];
+ pending_merge->pending_merge_kyc [color=red];
+
+ pending_merge_kyc->pending_merge [color="green"];
+
+ pending_withdraw->pending_withdraw_kyc [color=red];
+ pending_withdraw->pending_withdraw_aml [color=red];
+ pending_withdraw->done [color=green];
+
+ pending_withdraw_kyc->pending_withdraw [color="green"];
+
+ pending_withdraw_aml->pending_withdraw [color="green"];
+}
diff --git a/images/transaction-push-debit-states.dot b/images/transaction-push-debit-states.dot
new file mode 100644
index 00000000..3f17c56e
--- /dev/null
+++ b/images/transaction-push-debit-states.dot
@@ -0,0 +1,32 @@
+digraph G {
+
+ initial[label="", shape="circle", xlabel="peer-push-debit"];
+ pending_create[label="purse-create"];
+ pending_qr[label="ready"];
+ aborting_delete[label="delete-purse", style=dashed];
+ aborting_refresh[label="refresh", style=dashed];
+ done[label="done", shape="box"];
+ aborted[label="aborted", shape="box"];
+
+ subgraph {
+ rank = same; done; aborted;
+ }
+
+ subgraph {
+ rank=same; pending_qr;aborting_delete; aborting_refresh;
+ }
+
+ initial->pending_create;
+
+ pending_create->pending_qr [color=green];
+
+ pending_qr->aborting_delete [color="blue", style=dashed];
+ pending_qr->aborting_refresh [xlabel="timeout"];
+ pending_qr->done [color=green];
+
+ aborting_delete->aborting_refresh;
+ aborting_delete->done [color="red", label="already\nmerged"];
+ aborting_delete->aborting_refresh [color="red"];
+
+ aborting_refresh->aborted;
+}
diff --git a/images/transaction-refresh-states.dot b/images/transaction-refresh-states.dot
new file mode 100644
index 00000000..4b67c88e
--- /dev/null
+++ b/images/transaction-refresh-states.dot
@@ -0,0 +1,27 @@
+digraph G {
+
+ initial[label="", shape="circle", xlabel="refresh"];
+ pending[label="refresh"];
+ //aborting[label="refresh", style=dashed];
+ //aborted[style=dashed];
+ done[label="done", shape="box"];
+
+ subgraph {
+ rank=same;
+ pending;
+ // aborting;
+ }
+
+ subgraph {
+ rank=same;
+ done;
+ //aborted;
+ }
+
+ initial->pending;
+
+ //pending -> aborting [color=blue, style=dashed, label="abort"];
+ //aborting->aborted;
+
+ pending->done [color=green];
+}
diff --git a/images/transaction-refund-states.dot b/images/transaction-refund-states.dot
new file mode 100644
index 00000000..d436fea3
--- /dev/null
+++ b/images/transaction-refund-states.dot
@@ -0,0 +1,8 @@
+digraph G {
+
+ initial[label="", shape="circle", xlabel="refund"];
+ pending_accept[label="accept"];
+ done[label="done", shape="box"];
+ initial -> pending_accept;
+ pending_accept -> done;
+}
diff --git a/images/transaction-withdrawal-states.dot b/images/transaction-withdrawal-states.dot
new file mode 100644
index 00000000..9163c889
--- /dev/null
+++ b/images/transaction-withdrawal-states.dot
@@ -0,0 +1,45 @@
+digraph G {
+ initial_manual[label="", xlabel="manual" shape="circle"];
+ initial_bank[label="", xlabel="bank-integrated" shape="circle"];
+ pending_brr[label="bank-register-reserve"];
+ pending_bc[label="bank-confirm"];
+ pending_ewr[label="exchange-wait-reserve"];
+ pending_wc[label="withdraw-coins"];
+ pending_kyc[label="kyc"];
+ pending_aml[label="aml"];
+ done[label="done", shape="box"];
+ aborting_bank[label="bank", style="dashed"];
+ aborted_bank[label="aborted", shape="box", style="dashed"];
+ suspended_ewr[label="suspended(exchange-wait-reserve)", shape="box"];
+
+ subgraph {
+ rank = same; initial_bank; initial_manual;
+ }
+
+ subgraph {
+ rank = same; pending_aml; pending_kyc; pending_ewr;
+ }
+
+ subgraph {
+ rank = same; done; aborted_bank;
+ }
+
+ initial_bank->pending_brr;
+ initial_manual->pending_ewr;
+ pending_brr->pending_bc [color="green"];
+ pending_brr->aborting_bank [style="dashed", color="blue", label="abort"];
+ pending_bc->pending_ewr[color="green"];
+ pending_bc->aborting_bank [color="blue", label="abort", style="dashed"];
+ pending_ewr->pending_wc[color="green"];
+ pending_wc->pending_kyc[color="red"];
+ pending_wc->pending_aml[color="red"];
+ pending_kyc->pending_wc[color="green"];
+ pending_aml->pending_wc[color="green"];
+
+ aborting_bank->suspended_ewr [color="red"];
+ aborting_bank->aborted_bank;
+ pending_ewr->suspended_ewr [color="blue", label="suspend"];
+ suspended_ewr->pending_ewr [color="blue", label="resume"];
+
+ pending_wc->done;
+}
diff --git a/images/transaction-withdrawal-states.svg b/images/transaction-withdrawal-states.svg
new file mode 100644
index 00000000..ab33f4f6
--- /dev/null
+++ b/images/transaction-withdrawal-states.svg
@@ -0,0 +1,16 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1126.6875 605.2129204635194" width="1126.6875" height="605.2129204635194">
+ <!-- svg-source:excalidraw -->
+ <!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1dWXPaWrZ+P79cIuV+uV11UO956DdcdTAwMDeP8Yhnp7uLkkFcZjZcdTAwMDZcZlwiXHUwMDE4us5/v2tcdTAwMTPbmoVEXHUwMDA0tjuQVGJrYkta69vfXHUwMDFh93//+PJlw530nY1/ftlwnmt2p11cdTAwMWbY440/zfZcdTAwMWbOYNjudWFcdTAwMTeZ/T7sjVx1MDAwNrXZkS3X7Vx1MDAwZv/5j394Z1i13uPPs5yO8+h03SFcdTAwMWP3L/j9y5f/zv71f0+n0+5cdTAwMGad2eGzXHUwMDFkvi9cdTAwMTI8vPW41519KWNcdTAwMWNjLlx1MDAxOHo7oD3cgi9znTrsbdidoePtMZs2ut9cdTAwMWYvXHUwMDBm8SZSna/lRn3y4+vm961971tcdTAwMWLtTufcnXR+3pFda41cdTAwMDa+MVxy3UHvwblu191cdTAwMTbsx6Htb+dccntw/95Zg96o2eo6Q3P33kB7fbvWdifmOsjbanebs2t4W57ht1x1MDAxMsXM8lx1MDAxZYI5qYSJsihW3p/QaMq9Tm9gRvM3NPt447mza1x1MDAwZk1cdTAwMThUt/52jDuwu8O+PYB35Fx1MDAxZDd+uU9C3ja1nHaz5Vx1MDAwNrdccp3ZwyaIS4SEVuxtj/mS/n599tb/439cdTAwMWPd+svjeFx1MDAxNVx1MDAwM09cdTAwMTDIy5a/vOGa47fDXHUwMDAy5Fx1MDAxN1wi3+udnpy590fV/d3t4W65W3rYx7s7o7dbXG5InD1cdTAwMTj0xlx1MDAxYm97/nr5yVx1MDAxYuioX7d/XG5cdTAwMTJcdTAwMTZcbp4gXHUwMDExRFx1MDAxMem9mU67+1x1MDAwMDu7o07H29arPXiy94fvTlwiXHUwMDEy7zrPbpy4Y0ySxF0gilx1MDAwNVwiKLu437BRs1692Ny8arn9XHUwMDBlc7ed5v3Dx1x1MDAxN3dtXHUwMDExRSnRXGJcdTAwMGVGWlxuXHUwMDExlH1CqMWET/bJ8oRfXHUwMDEyXHUwMDBiXHUwMDFlOMKEIFx0j5/wXHUwMDE4ZaBhZcBCS65cdTAwMThcdTAwMTc5dCEgR7mEvlrHlZPmLVx1MDAxZlx1MDAxZN90689V1GvsbrayXHT9n2nXvd6zb852XHUwMDBlbmt3O6x92DrZvmq0xLspkye0va573p7O0Fx1MDAwMlx1MDAwNbbu2I/tzuR1bvo5QKNlMMC+0623u83/u7O7XHUwMDBmpYHTbFx1MDAwZl1nXHUwMDAwP1xmncFcdTAwMGbn71x1MDAxYoHjNzvtptHEjVx1MDAxYTx9Z1x1MDAxMFBSt1xys9vbXHUwMDAxbq/v7a3BXGLsdtdcdTAwMTns18N30lx1MDAxYrSb7a7ducg5XHUwMDFheCrO3quYYVx1MDAwYvOFXHUwMDEwRbPwRm/+ZIIjybxcdTAwMDPmXHUwMDAxyrTEtlx1MDAxZPdwwsfV7bPt5lx1MDAxZdrZKqNPXHUwMDBmKJjolU2mwlwiXHUwMDAyPoTDMLjIiCeMSSm5f2r4jICiq1+P1PHB3f35qDYhT4eH51x1MDAxN7WtXHUwMDAyrlvtoVx1MDAxYqEn3XvcOd67KO9tXHUwMDFkTqe4KKCiijKk/Cq5OqBcdTAwMDJIabRcdTAwMDeP8Pv7QlTsOFxuXHUwMDAyJ51cdTAwMDROmFxiTaTwP/x56DQ43X0+rO+ebH7rVJpXnD1ccp+ao0+PTlx1MDAxY1nKXHUwMDBmTuGhXHUwMDE1iE6KW2ZcZkhgRDn28ZdUcMJSXHUwMDEwtiq281x1MDAwYlx1MDAxNP9dwKl2dHQoKrRzclx1MDAwMbjfqT2cVS7bO1x1MDAwNVxcVz6gve/1w52n3lx1MDAwZd+/vNpcdTAwMTblXHUwMDFk5lx1MDAxNlx1MDAwN3paS+1X9ZWAnvNcXGuBkjilsd12352dzVx1MDAxYk1BXHUwMDAwqMJcdTAwMWLfXHUwMDAwXHUwMDEwXHUwMDAx9mlMVXZ6dqBF9aiFXHUwMDAw+cb1SvVH9bi2Jc4+O1x1MDAwMMJuv7GHdWhkXHUwMDA14lx1MDAxZqNcdTAwMTbicFx0ijiWXFx6ryZccv9cdTAwMTTMVJxivVx1MDAxYXK2LDw57Hy7Kk3LpW9cdTAwMTdqs4KeXGI/qI6/XHUwMDE2cF37qDRq7D/2x+W287jb2Fx1MDAxZZRGN91cdTAwMDKuy1x1MDAwNuPj6lX3YtRvnNU3b79ccvTJ5XlcdTAwMDHXXHUwMDFkbd/dTntccnlwVG0+j+2DwbCunlxuuO7p3bXTt9s7d/2ansjpd/uodXpTwHVblYM6XHUwMDFlXHUwMDFkXZM9Nd1/mpQxLu3vXHUwMDE2Md7y0Xf7QY9cdTAwMWVcdTAwMWa6R6Rywrf2z68zvrf581x1MDAwYlg+XHUwMDAwUiufX8Ztt2U80/AzcNp2d/huc0vaSIqZV2TyvKJcdTAwMThcdTAwMTJcYqZ4XHUwMDBmZufNKy1ero/Y6Vb3hlxyXHUwMDBlx996XHUwMDFk0lNHXHUwMDFmfl7BSllcdTAwMDKDsa0kwljCr4F5XHUwMDA19lir8VwiYs0sQuEjXHUwMDE5cCtGZSarn0vgYFxcMW/Uy5xXPlx1MDAxYv6Xjm7s891v7jnWXHUwMDA3zafrybGub06LwidGNPU5W1aFT1x1MDAwZpNcdTAwMWHwzKdRe+DU31xymlx1MDAxMlx1MDAwNlFcdTAwMTDblcnmvlx1MDAxNPDkUY5g3tbj9aTBkcNrpfubelXdu5uT+4+OSlRahFx1MDAwM9vFRCtFlD+iMFx1MDAxM1x1MDAwZYFWXHUwMDA2SsJiKi8oKYowXHUwMDFjr1dj7H82knfLdy7F2eHhj7vrZ4Tr181Nd3hRXHUwMDA0XHUwMDE5u3BPqpVK9/Fq1FM2XHUwMDE5XFxM8cWgMLDDmHHuV/SVgJ392Hl/sEtcdTAwMThENrB78T6r2lC3L8ZyKnn1ujK9ZY1T6rufWEQ0SEBMVF8yrYVmXG6mXHUwMDFjXHUwMDEyXHUwMDAwXHUwMDAyXGa2aDxcdTAwMTC8KbCUluI+b11cXKDeU+AoXHUwMDFjXHUwMDE1hSjvXHK0OVx1MDAxMehcdTAwMDXJzHSjNCGR6Fx1MDAxOOxcdTAwMTOJMXjOqFx1MDAwMG3x9idPUrmQbmnIsSSzc9NtNStcdTAwMDPqdivDxj3vU9W7vEGFIVx1MDAxMqJIXG6/NmZFpDiQaVxmelOn69Pu3LC1WjyKjDdcdTAwMGZcdTAwMWFdno1vt++/yU6XnreOyPbZ1eDie1x1MDAxNI1+vpOguUQ0sVx1MDAxMOGaU05cdTAwMDWYKziSclx1MDAwNNRcdTAwMDVhaaCGXG5FPD+c5z/DXHUwMDE2j7/CXHUwMDFiXCIpamEsXHUwMDE4hW9iTCuf1+x3XHUwMDA2qCyZUK/+RuNcIuVcdTAwMDT54i1cdTAwMWVwUYLDW1+RS1x1MDAwYpjmcaZYf0bkip3afLLY/3H+eD65Kk1cdTAwMWX7u93L45NvdPqjk89PXHUwMDA0gkRcdTAwMTdcdTAwMDKCfq9cdTAwMWRcdTAwMWX7v3wjRP7horef//Nn7NGKJYi1+ZRgXHUwMDFhXHUwMDBlSDSed7lkNZldL6Ih3vVcIk+sY1x1MDAwZt1y7/Gx7cJzOzX3XHUwMDFjme1cXHvgfm3P4CW8XHUwMDBmQCdhz+ysTVx1MDAwM1x1MDAxMi3HjqBcdTAwMTec59/nR/h4VIqXhFxmXHUwMDFjqURcdTAwMDT5aS9xjCk8NE98X1LBiCVxOk1C2uJYXGKJXGKRiKM4rz5cdTAwMTWWt/V3xqE4ooRNbqdSftLjS1dMdDNS+GZFRCYvY1x1MDAxOHBcdTAwMDLDKFx1MDAxMFx1MDAxNV7pgclq+Fx1MDAwMsriNFx1MDAwN+bS/+6++mPtTixNwFwisPWXacJju17vOElMYd4kXHUwMDFlJlx1MDAwZpnuJlx1MDAwZolIj7Gnk1xipSxcdTAwMDKYppFA8Lp0mEMgYVwibFx1MDAwMl6iwlx1MDAwNGPfg/WTXGLpv0KMWSORJSmYTEhcdIBJTflaefORXGJFsFJCRnONjeKy5JxcdTAwMWMtSSDHe+lcdTAwMWOCsNJcdTAwMTPTu/vPN1ff3DOpyr3p7l0+XHUwMDBlgTVeLNO0UFx1MDAwZSFVglTPdoblOVx1MDAwYoVIvpxQiZf7dVx1MDAwNuGTspe6jv1cZqVcdTAwMTUz5KyNzNMsIVx1MDAwYqZjMPI4pkxxqoX0XHUwMDFk1bT7RsEtrVxiY0RqjKSZ9iOCXHUwMDFj4C5JY0pPXGJcdTAwMGKOyeR4c1x1MDAwZcKPXHUwMDA0N+RLxFxmisx4XHUwMDA0cDKtjc80ql3F0qZ44c9Gm7RFmVx1MDAxOS3Ya2DY+fzuM1x1MDAxY2bAaFx1MDAwMzllUVx1MDAxY8bY5F1QSlx1MDAxOeWIK+5LI37DYawsb+vvXGa9sbyJI4VcdTAwMTFcdTAwMTUyljeh8Ma3Klx1MDAwZlx1MDAwZXRXaZEl7TFcdTAwMWZvgrdM5EKprK+86dHujuzOl1d+8Vx1MDAxMbjSXHUwMDFjrlx1MDAxMuZKiXeQy+WbmiCdxo+4ilx1MDAxNHJpnJB7Po5I9Jve8TyEh9wpmzr/i1qXx2tiXGZuQUWs14Ql50oweCMs4CUuzIqBOZAulGNZKC/B/qP5SphCelWab1ZGJi9QUa5cYqJIc1x1MDAxZs9/m5P1YsQgvY4lRFZcYlx1MDAxNVQrXHUwMDEzJ8UwXHUwMDFlRiODkMsmXHUwMDAy6cnJqYCjw4CjQ4WjnuqmXHUwMDAwXHUwMDBlyzPNr1x1MDAwMcdYWFxiI8WFikCLsbBcdTAwMTIrmrFcdTAwMDamxVx1MDAxOCZZsiA+P94w5lx1MDAxZL48vMms7KDrXHUwMDE0MS6ZIFxiU8wkYr6jfuq6WlxmcPJYXCJcdTAwMDTIXHUwMDFmhb9MXGKGXHUwMDE4VZEx8KjQXHUwMDE1izfpScZpeCNolOCE8MZcdTAwMGJJv1x1MDAwMo63xWM43jy9XHUwMDA2XHUwMDFj/0NPXHUwMDA2XHUwMDFjalJzOIlcdTAwMThcdTAwMTZcdTAwMDa+k2vKYWJcdTAwMTXLMDY+XGLcUP/RXFysXHUwMDAybjKruqE3XGZmXGIuKZZcdTAwMTgzLaL8JkotMsFNeiFImN9cdTAwMTCkiFx1MDAwNNNQMcZcYot6Y5bu6EhPPk13OMtcdTAwMTDgSJlULuJFhGJcXMoqLXHv93Fk5DGpJMcgvP7Cl4yJnsCMXGJdJIUmXHUwMDFkcsCUpp4v8d0gp+STL/NRvjOWhzqZNVx1MDAxZVlcXEgktYRnJVx1MDAxOIb/I/qOXHUwMDE3dLeml1x0XHUwMDA0UVx1MDAwN0BPKsk15lr781x1MDAwZlMsu4JBJz0zPVx1MDAxNXQkXHUwMDBlgVx1MDAwZeZyTraeisOcPFZcdTAwMTVcdTAwMTWsUZO/OeZcdTAwMTCFhGKcxnlxUiBcdTAwMDcp48lWmTrn5MNcdTAwMWOmNWPvXHUwMDFmXVJcdTAwMDHEKamV2FV51N300EFaKcSYMn2iXHUwMDE48+qLU1S+WLKDLGomXHUwMDFljICbaoJ8zkBcdTAwMGb6UFT0ioWd9Jz2VNtcboWpXHUwMDBlnUd1YmM265S73ExcdTAwMDdpJlx1MDAwMvjhwVx1MDAwZU/MuONUM4r98Z/imFx1MDAwZXzePy+O+Y9cdTAwMDa5+mA8XHUwMDA3RsSAXlx1MDAwMEHlXHUwMDAyM1x1MDAxZkIm63omvEmvO1xu4p7E5lx1MDAwZmFcdTAwMDRLXHUwMDEzpY/aVkv35aTXuqThjVx1MDAwZZtWMNvNYzkxeCPzuHLWeGOAXHUwMDFlXGI6kjGdXHUwMDAwN1x1MDAwMqG/MMuh2qTqcVxcPN5cdTAwMTBEpHp/llNS/sNLIFmrQJw86k4lo8ByMEOaXHUwMDAy4aQxXHUwMDA0XHUwMDAzR9564Vx1MDAxZVx1MDAxZMQxTFeawNtcdTAwMTNgjEad2MtnOen1LGmoXHUwMDAzc1tu2GExISu5Ln3KXHQ7QImxXHR7xFVERTe+wlx1MDAwZeGESuFv/1RcdTAwMWPqXHUwMDAwmHlP7d1YTiBkVZL0Q4FcdTAwMGWymDa9d1x1MDAwMfZcdTAwMTUjiKpcdTAwMTiesyDkpFc2XHUwMDA2xsBcdTAwMDHsNOYwTVxiqUGG3lx1MDAwMXHSK93SXHUwMDEwh9Bw0Fxu03nuXHUwMDFjXHUwMDE2U9ok1oZVXsNKU1x1MDAwMVY4jlxyWtHkNGTjuORcZqPis3JcYlKcLtSZplimw4I1QWIltlVmhTf+W1x1MDAwNbDDuCZUc0SjoCNcIu+8cJpcdTAwMDPsRjEuqZaKXHUwMDEzhGJAJ0bwilx1MDAwNZ3HXG5h/PT2aEBa9ye60aj27tzLLFx1MDAxObpUcFx1MDAwYpBSgCBcdTAwMTPKKceRXHUwMDFl1yxcdTAwMTA2lzGFXHUwMDEyiFnxKb7r8u9cZtm5XHUwMDE0XHUwMDBi89hj678xSfYlXHUwMDBiXHUwMDEwd4X8LuiCSsCX2m+bS6nRQlxc6jX3177rXHLgkj87wrq90tjuwE1/7LLquWPOk/WrmpXecHwxvO91z76fXFztXf64XHUwMDFmVTPpOtdcdTAwMTZJ0fXk9tOeqsNcdTAwMTFcIraT1VrX5+s6zFx1MDAxMJrKXHUwMDA0wyZcdTAwMTJKetN0rChnpjVH0Zr+8K30fPe1fDqYXGZcdTAwMWKX4+rz4W75pohcdTAwMWW2m8/l8+bR4XZv52Javju4eqo9tVhcdTAwMDHX/aBccrZcdTAwMDPINOuqN1Nvo+hG4T9cdTAwMDE0pVx1MDAwZTpcdTAwMGY28SmvXHUwMDFlXlSOTvhXuzK5OCw/tkQpKzaxWfNVKYlmvlxcjp91QirQe1rymDohyS1kyoRcdTAwMTAzlHxe1+g1Nr1+8atcdGRKXHUwMDE04cHHxpaSnb1MXHUwMDFiXHUwMDAyI1x1MDAxNnK7pILTskBkqVxyq7nQiP06iFx1MDAwMFWwXHUwMDFiZi2Ocagh1EdcdTAwMDWQxFx1MDAwMedcdTAwMDFcdTAwMGZRumKD7UN971xc9tzK87j6vbo7yFx1MDAwMlx1MDAxZVxcXHUwMDE5IyXUwa7ERNByicFcZmO6zOk3t8aJ1y9+yXyhYK5cdTAwMDSEPNOaUVx1MDAxOM4wOe2Fw8QvcJgs6lxmlGChlnRhdf50lCBtzHmUunzxtPM8Pnualvdr6OG2uv3sjlkmRmCySswn3lphxFxu9FvxkWqvg4OYXWHtmFjMMaGYXGZEcf1+icRKRaWQ1tpfyF2Qoi+rwfgvdJBLve4v9MpMve5SXHUwMDFiXHUwMDBlc66Qon5FX1x1MDAxNPBAXHTcNlx1MDAwMMik9Frj/MFb32VcdTAwMWJ4XHUwMDFl6EufmtLLs0mkfFx083n1kjQmy054h63rl/yPPSXJjpmIXHUwMDBlim2XkNyQXHUwMDEzS8KI4EosoUJbKsJcdTAwMTcyKootYVxuxp/ntpejgbQ8sZLqg3Tf6JdAuJpwxKSCXHUwMDE3RuWsRY3vqJewXHK1lD+wIVx1MDAxNsxcdTAwMGJOt2u+XHUwMDA08/SQRkJSRYlWTEfT9JZejZBudqeBXHUwMDE2o1HQQniRXCLvPPHrmiY2sX9zzGJmtaCEclx1MDAwNK9PQCRjXHUwMDA2mXRcdIZcdTAwMTfqozVcdTAwMDeyXHUwMDE0oNb7l0BcdTAwMDWLvFdcdTAwMTK7zoFAXHUwMDE0UUEkxZQhMFVQlvrqTHiT7oRccuJccmZcdTAwMDKb+cW0/qYwmJhCc2vpqcHpfv30JD1cdTAwMWUlSvNcdTAwMWJL8Lj84Fx1MDAxY6CzroHaMI3LgfKA7MY5jFN4kpCCXHUwMDEyojItp/kpa6B80jX7dVx1MDAxNaiTq49cZqKaXHUwMDBizqTQXGZcdTAwMTNCovkqatao1ud5WVxmhzJDoUlcdTAwMTXWilx1MDAwM+PhXGJcdTAwMGKAQsGiRVmhPFx1MDAxNVx1MDAxZVx1MDAxZFTBqJSeXHUwMDA3kZrIx8JcdTAwMTVSJYLRvPZaOMZ8y1NcZr5cdTAwMDYlw49cdTAwMTVcdTAwMDU0kFwitvtEYjJccjfAXHUwMDAxnPt/XHUwMDE3kzBLOH55mJSjvVx1MDAxNoZ5XHUwMDA0SFxicCBhoElG0/ikNVusXGJcdTAwMWUqMWl2i0JSep5cXJhcdTAwMWFcdTAwMDVcdTAwMDZcdTAwMTXTXHUwMDFklK1cdTAwMWGS0mOXqZDEI1xycehcXJ6kY1x1MDAxYeLkcZivXHUwMDExyVxcmJilWqSMNc54onGGlSnaVIs1OU7HJG56rLy/caZcdTAwMDM9cVZSzZCr+1x1MDAxNVVcdTAwMWEsZK25lkxRXHUwMDFlh0mmmp9cdTAwMTBt+Fxuw2zB8obK0b3dOb9wXHUwMDE0yDSq3Fx1MDAxY4vRtmBJg9JIc6lcdEVIIc6i1G3pLVx1MDAwMNPDMKlcdTAwMTCEwlx1MDAwNVVcdTAwMWPPbZGzttSKaMklKfyN7zmaXFw2jqlZXHUwMDEyXHUwMDA00YWWavlcdTAwMWOsiIdcbjlXgUF5XG7HkaBaXHUwMDBiQlx1MDAxMFBcdTAwMTGmo71pwCaCl2SWcFGEY81pRFx1MDAwMjIhUHqMPjwkoYhEiME/IFRxpChcdTAwMTC1Xz4pSlx1MDAwZuCmeqxRtH9O0lq8aUG2df+cvIhcdTAwMDTIolx1MDAxMEyrcWZcdTAwMWFOXjtcblx1MDAwM2owU19YPCRJLlx1MDAwNH3/XCLPYNAsQ5DtPVx1MDAxYe7kKMikXHUwMDE4McExvGopaJxccqUt5Ft7XHUwMDEyq1x1MDAwNfua5oAwjrhcdTAwMTRCI1x1MDAwNcROqJhcdTAwMTjbXG5qRFNzQ/K5logkcyBcdTAwMGJcYn9cdTAwMTSzXGLKXHUwMDEzZVuDllx1MDAwMS2kkVnKJDYjKjnMhlx1MDAwMa9MXHUwMDBihiV4vD9cYmhcdTAwMTFcdTAwMTZCobkncFx1MDAxOThcdTAwMDGEcVx1MDAxNbiVo5idXGI9W1x1MDAxYUoyKjWiMb0rhCWD62cvXHUwMDE5uIyTnChCXHUwMDAxLVxyJ4evXHUwMDA2RI2MKlxun1x1MDAwNUNXevpZeotUajHt/3gqM1x1MDAwMzKE51x1MDAwMJmIW8iTiDyLUKyBzJhcclxcaUZEXFxcdTAwMTlcdTAwMWFJzuw0/epgOpd6kb4+vkF/VFx1MDAxNMPCfzimYt5cdFxcXHUwMDA2XHUwMDAzfYTMO0OElthcdTAwMDTwWFx1MDAwNe7laZBoVsTSWDCpTXdcdTAwMDNcdTAwMWVNSogpZi9cdTAwMWPopKZYzlp5MMYkj1x1MDAwNlx1MDAwM5dP0SZ7XHUwMDE3ZVRcdTAwMWJ+bU2eL5zt+8vb4e12zFx1MDAwMsZxa15xaVx1MDAxMWo+XHUwMDFjSC9cdTAwMTMhn1x1MDAxN1x1MDAwYoJcXEzeOmNcdTAwMTZb560vXFyggtisYDY2LyGlnFx1MDAxZVx1MDAxYo87XmhF9TnudsL93fBcdTAwMTfIqa73ur5cdTAwMDf/XHUwMDAxc6eDXHUwMDAzzJMjzVSf3d7uXVx1MDAxZXSeXHUwMDFhjc5cdTAwMTlqnJRojCU0cGruT0FcdTAwMGbpmlxiL2RcdTAwMTXyKcfpl4hTKL1WqFx1MDAwNIVcdTAwMDJcdTAwMTRSUlx1MDAxMlx1MDAxYVx1MDAxYlNPXkJcdTAwMDZcdTAwMTBcXFIm2FwiVk9qIchp+ei7/aBHj1x1MDAwZt0jUjnhW/vn113fRFx1MDAxMmGhb3uyrNLJXHUwMDA14nn67qTI9vTZXHUwMDFll2Xv5vpp4tT2Me2cbLZOMss25eG2l0Cg0dxmLCQmoXa9Lm2ycDNlukqS2HrGqMT71mOjZi2w4pvNcbPKZZ5cbpxcdTAwMTRcdTAwMDFMjyzOXHUwMDE3wEjKXHUwMDAwJ3NLarGKQVe6XtRcIlFcdTAwMDDhKUpcdTAwMTZYh8JcdTAwMTecS+x2iFx0ZVx1MDAxMv5ZqMlqKrwutz5eXHUwMDEyhvOkXHUwMDFlpEh39Xxvc/v4tMbY6c5Ne7pzONk9j2lgniDdXFxcdTAwMDEzUTIs4Gx+zTiOQ9g1fUimXHUwMDBmTFx1MDAwYizi3aZcIrk4gVwiZLrzL4GPXHUwMDBiKnGeou5cdTAwMTRcdTAwMTk8xjfHN+eVPfvrNjqc0uOdrVY5x1x1MDAxNFx1MDAxZmGvVMxlr7HefJonXHUwMDAy+XvJn6BI0EBuZ1x1MDAxNvHDSFx1MDAxYfN7XHUwMDE5S3VwxvzK8Evyl86FU72xLFxcOZHBcsIsLlx1MDAxZCfP5L4uMTViXHUwMDA3z1x1MDAxNmPB4lxmquRWO4JgTTRbRoGpcfq9fzpOySde5oM/2oJVXGZcdTAwMTNuVlx1MDAxYmNUU1x1MDAxNrtsi7CIKVx1MDAxOEVaaa1cdTAwMTFwtIhcYmTylaZ7Rb6EyjlAlJRSXHUwMDE0xiUxjum7XFxkTOiPl3ewYff75y6I0dtdbPxoO+OvUXX+W2P2MefPXHUwMDA2YFTZmSnMX3/89f9yoaBcdTAwMWQifQ==<!-- payload-end -->
+ <defs>
+ <style class="style-fonts">
+ @font-face {
+ font-family: "Virgil";
+ src: url("https://excalidraw.com/Virgil.woff2");
+ }
+ @font-face {
+ font-family: "Cascadia";
+ src: url("https://excalidraw.com/Cascadia.woff2");
+ }
+ </style>
+ </defs>
+ <rect x="0" y="0" width="1126.6875" height="605.2129204635194" fill="#ffffff"></rect><g stroke-linecap="round" transform="translate(10 111.99999999999994) rotate(0 11 11)"><path d="M22 11 C22 11.64, 21.94 12.28, 21.83 12.91 C21.72 13.54, 21.55 14.16, 21.34 14.76 C21.12 15.36, 20.84 15.95, 20.53 16.5 C20.21 17.05, 19.84 17.58, 19.43 18.07 C19.02 18.56, 18.56 19.02, 18.07 19.43 C17.58 19.84, 17.05 20.21, 16.5 20.53 C15.95 20.84, 15.36 21.12, 14.76 21.34 C14.16 21.55, 13.54 21.72, 12.91 21.83 C12.28 21.94, 11.64 22, 11 22 C10.36 22, 9.72 21.94, 9.09 21.83 C8.46 21.72, 7.84 21.55, 7.24 21.34 C6.64 21.12, 6.05 20.84, 5.5 20.53 C4.95 20.21, 4.42 19.84, 3.93 19.43 C3.44 19.02, 2.98 18.56, 2.57 18.07 C2.16 17.58, 1.79 17.05, 1.47 16.5 C1.16 15.95, 0.88 15.36, 0.66 14.76 C0.45 14.16, 0.28 13.54, 0.17 12.91 C0.06 12.28, 0 11.64, 0 11 C0 10.36, 0.06 9.72, 0.17 9.09 C0.28 8.46, 0.45 7.84, 0.66 7.24 C0.88 6.64, 1.16 6.05, 1.47 5.5 C1.79 4.95, 2.16 4.42, 2.57 3.93 C2.98 3.44, 3.44 2.98, 3.93 2.57 C4.42 2.16, 4.95 1.79, 5.5 1.47 C6.05 1.16, 6.64 0.88, 7.24 0.66 C7.84 0.45, 8.46 0.28, 9.09 0.17 C9.72 0.06, 10.36 0, 11 0 C11.64 0, 12.28 0.06, 12.91 0.17 C13.54 0.28, 14.16 0.45, 14.76 0.66 C15.36 0.88, 15.95 1.16, 16.5 1.47 C17.05 1.79, 17.58 2.16, 18.07 2.57 C18.56 2.98, 19.02 3.44, 19.43 3.93 C19.84 4.42, 20.21 4.95, 20.53 5.5 C20.84 6.05, 21.12 6.64, 21.34 7.24 C21.55 7.84, 21.72 8.46, 21.83 9.09 C21.94 9.72, 21.97 10.68, 22 11 C22.03 11.32, 22.03 10.68, 22 11" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(285.21667098999023 16.849999999999937) rotate(0 136.10000610351562 11.5)"><text x="136.10000610351562" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">pending(bank-register-reserve)</text></g><g transform="translate(285.21667098999023 110.99999999999994) rotate(0 113.13333129882812 11.5)"><text x="113.13333129882812" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">pending(bank-confirming)</text></g><g transform="translate(285.21667098999023 189.49999999999994) rotate(0 142.5500030517578 11.5)"><text x="142.5500030517578" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">pending(exchange-wait-reserve)</text></g><g transform="translate(285.21667098999023 279.99999999999994) rotate(0 121.5250015258789 11.5)"><text x="121.5250015258789" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">pending(withdrawing-coins)</text></g><g transform="translate(135.88333129882812 406.99999999999994) rotate(0 97.11666870117188 11.5)"><text x="97.11666870117188" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">pending(kyc-required)</text></g><g transform="translate(361.7583312988281 500.99999999999994) rotate(0 98.24166870117188 11.5)"><text x="98.24166870117188" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">pending(aml-required)</text></g><g transform="translate(539.0749969482422 383.99999999999994) rotate(0 88.92500305175781 11.5)"><text x="88.92500305175781" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">pending(aml-frozen)</text></g><g mask="url(#mask-URwYEjJ7ln3ShM2ERVrTZ)" stroke-linecap="round"><g transform="translate(32.474046463766854 113.11643025449885) rotate(0 120.76297676811657 -42.49546412822369)"><path d="M0 0 C14.09 -12.85, 44.27 -63.26, 84.53 -77.12 C124.78 -90.97, 215.36 -82.12, 241.53 -83.12 M0 0 C14.09 -12.85, 44.27 -63.26, 84.53 -77.12 C124.78 -90.97, 215.36 -82.12, 241.53 -83.12" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(32.474046463766854 113.11643025449885) rotate(0 120.76297676811657 -42.49546412822369)"><path d="M213.1 -73.51 C219.6 -75.71, 226.09 -77.9, 241.53 -83.12 M213.1 -73.51 C221.47 -76.34, 229.83 -79.16, 241.53 -83.12" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(32.474046463766854 113.11643025449885) rotate(0 120.76297676811657 -42.49546412822369)"><path d="M213.58 -94.03 C219.96 -91.54, 226.35 -89.04, 241.53 -83.12 M213.58 -94.03 C221.8 -90.82, 230.02 -87.61, 241.53 -83.12" stroke="#000000" stroke-width="1" fill="none"></path></g></g><mask id="mask-URwYEjJ7ln3ShM2ERVrTZ"><rect x="0" y="0" fill="#fff" width="374" height="296.23286050899776"></rect><rect x="62.24166488647461" y="17.599999999999937" fill="#000" width="109.51667022705078" height="36.8" opacity="1"></rect></mask><g transform="translate(62.24166488647461 17.599999999999937) rotate(0 90.99535834540882 53.020966126275226)"><text x="54.75833511352539" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="16px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">bank integrated</text><text x="54.75833511352539" y="18.4" font-family="Helvetica, Segoe UI Emoji" font-size="16px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">withdrawal</text></g><g mask="url(#mask-zORtjM_IGEsGCn-kI1GFu)" stroke-linecap="round"><g transform="translate(36.276609398310484 134.2675791369706) rotate(0 120.86169530084476 37.70777219806918)"><path d="M0 0 C13.12 11.79, 38.44 59.28, 78.72 70.73 C119.01 82.19, 214.56 69.07, 241.72 68.73 M0 0 C13.12 11.79, 38.44 59.28, 78.72 70.73 C119.01 82.19, 214.56 69.07, 241.72 68.73" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(36.276609398310484 134.2675791369706) rotate(0 120.86169530084476 37.70777219806918)"><path d="M214.31 80.92 C221.53 77.71, 228.75 74.5, 241.72 68.73 M214.31 80.92 C224.92 76.2, 235.52 71.49, 241.72 68.73" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(36.276609398310484 134.2675791369706) rotate(0 120.86169530084476 37.70777219806918)"><path d="M212.89 60.45 C220.48 62.63, 228.08 64.81, 241.72 68.73 M212.89 60.45 C224.05 63.65, 235.2 66.86, 241.72 68.73" stroke="#000000" stroke-width="1" fill="none"></path></g></g><mask id="mask-zORtjM_IGEsGCn-kI1GFu"><rect x="0" y="0" fill="#fff" width="378" height="304.99999999999994"></rect><rect x="55.15833282470703" y="195.79999999999995" fill="#000" width="119.68333435058594" height="18.4" opacity="1"></rect></mask><g transform="translate(55.15833282470703 195.79999999999995) rotate(0 101.97997187444821 -23.824648664960165)"><text x="59.84166717529297" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="16px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">manual withdraw</text></g><g stroke-linecap="round"><g transform="translate(383 48.99999999999994) rotate(0 0.5 27.5)"><path d="M0 0 C0.17 9.17, 0.83 45.83, 1 55 M0 0 C0.17 9.17, 0.83 45.83, 1 55" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g><g transform="translate(383 48.99999999999994) rotate(0 0.5 27.5)"><path d="M-8.88 29.33 C-5.89 37.1, -2.9 44.87, 1 55 M-8.88 29.33 C-5.43 38.28, -1.99 47.23, 1 55" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g><g transform="translate(383 48.99999999999994) rotate(0 0.5 27.5)"><path d="M9.94 28.99 C7.23 36.86, 4.53 44.73, 1 55 M9.94 28.99 C6.82 38.06, 3.7 47.13, 1 55" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(384 141.99999999999994) rotate(0 0.5 22)"><path d="M0 0 C0.17 7.33, 0.83 36.67, 1 44 M0 0 C0.17 7.33, 0.83 36.67, 1 44" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g><g transform="translate(384 141.99999999999994) rotate(0 0.5 22)"><path d="M-6.99 23.5 C-4.19 30.69, -1.39 37.87, 1 44 M-6.99 23.5 C-4.02 31.13, -1.04 38.76, 1 44" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g><g transform="translate(384 141.99999999999994) rotate(0 0.5 22)"><path d="M8.05 23.16 C5.58 30.46, 3.11 37.77, 1 44 M8.05 23.16 C5.43 30.91, 2.8 38.67, 1 44" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(388 220.99999999999994) rotate(0 1.5 28)"><path d="M0 0 C0.5 9.33, 2.5 46.67, 3 56 M0 0 C0.5 9.33, 2.5 46.67, 3 56" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g><g transform="translate(388 220.99999999999994) rotate(0 1.5 28)"><path d="M-7.99 30.2 C-4.81 37.67, -1.63 45.13, 3 56 M-7.99 30.2 C-4.25 38.97, -0.52 47.74, 3 56" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g><g transform="translate(388 220.99999999999994) rotate(0 1.5 28)"><path d="M11.17 29.18 C8.8 36.94, 6.44 44.7, 3 56 M11.17 29.18 C8.39 38.29, 5.62 47.41, 3 56" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(297 317.99999999999994) rotate(0 -51 40)"><path d="M0 0 C-17 13.33, -85 66.67, -102 80 M0 0 C-17 13.33, -85 66.67, -102 80" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(297 317.99999999999994) rotate(0 -51 40)"><path d="M-86.15 54.53 C-91.74 63.51, -97.33 72.49, -102 80 M-86.15 54.53 C-91.73 63.49, -97.3 72.45, -102 80" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(297 317.99999999999994) rotate(0 -51 40)"><path d="M-73.49 70.68 C-83.54 73.96, -93.6 77.25, -102 80 M-73.49 70.68 C-83.52 73.96, -93.55 77.24, -102 80" stroke="#000000" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(253 397.99999999999994) rotate(0 41 -42)"><path d="M0 0 C13.67 -14, 68.33 -70, 82 -84 M0 0 C13.67 -14, 68.33 -70, 82 -84" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(253 397.99999999999994) rotate(0 41 -42)"><path d="M69.65 -56.66 C72.64 -63.27, 75.62 -69.88, 82 -84 M69.65 -56.66 C72.82 -63.67, 75.98 -70.68, 82 -84" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(253 397.99999999999994) rotate(0 41 -42)"><path d="M54.97 -70.99 C61.5 -74.14, 68.04 -77.28, 82 -84 M54.97 -70.99 C61.9 -74.33, 68.83 -77.66, 82 -84" stroke="#364fc7" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(385 313.99999999999994) rotate(0 2 91)"><path d="M0 0 C0.67 30.33, 3.33 151.67, 4 182 M0 0 C0.67 30.33, 3.33 151.67, 4 182" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(385 313.99999999999994) rotate(0 2 91)"><path d="M-6.88 154.04 C-4.23 160.85, -1.58 167.66, 4 182 M-6.88 154.04 C-2.77 164.6, 1.34 175.16, 4 182" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(385 313.99999999999994) rotate(0 2 91)"><path d="M13.64 153.59 C11.29 160.51, 8.94 167.43, 4 182 M13.64 153.59 C10 164.32, 6.36 175.05, 4 182" stroke="#000000" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(422 489.99999999999994) rotate(0 -4 -88)"><path d="M0 0 C-1.33 -29.33, -6.67 -146.67, -8 -176 M0 0 C-1.33 -29.33, -6.67 -146.67, -8 -176" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(422 489.99999999999994) rotate(0 -4 -88)"><path d="M3.53 -148.3 C-0.95 -159.07, -5.43 -169.83, -8 -176 M3.53 -148.3 C-0.14 -157.11, -3.8 -165.92, -8 -176" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(422 489.99999999999994) rotate(0 -4 -88)"><path d="M-16.97 -147.37 C-13.48 -158.5, -10 -169.62, -8 -176 M-16.97 -147.37 C-14.12 -156.48, -11.26 -165.58, -8 -176" stroke="#000000" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(524 489.99999999999994) rotate(0 20.5 -36.5)"><path d="M0 0 C6.83 -12.17, 34.17 -60.83, 41 -73 M0 0 C6.83 -12.17, 34.17 -60.83, 41 -73" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(524 489.99999999999994) rotate(0 20.5 -36.5)"><path d="M36.14 -43.4 C37.35 -50.76, 38.56 -58.13, 41 -73 M36.14 -43.4 C37.79 -53.45, 39.44 -63.51, 41 -73" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(524 489.99999999999994) rotate(0 20.5 -36.5)"><path d="M18.25 -53.45 C23.91 -58.31, 29.57 -63.18, 41 -73 M18.25 -53.45 C25.98 -60.09, 33.71 -66.73, 41 -73" stroke="#000000" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(558 377.99999999999994) rotate(0 -22.5 -31)"><path d="M0 0 C-7.5 -10.33, -37.5 -51.67, -45 -62 M0 0 C-7.5 -10.33, -37.5 -51.67, -45 -62" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(558 377.99999999999994) rotate(0 -22.5 -31)"><path d="M-20.14 -45.21 C-25.27 -48.68, -30.4 -52.14, -45 -62 M-20.14 -45.21 C-25.69 -48.96, -31.24 -52.71, -45 -62" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(558 377.99999999999994) rotate(0 -22.5 -31)"><path d="M-36.74 -33.16 C-38.45 -39.11, -40.15 -45.07, -45 -62 M-36.74 -33.16 C-38.59 -39.6, -40.43 -46.04, -45 -62" stroke="#000000" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(690.2916641235352 16) rotate(0 102.20833587646484 11.5)"><text x="102.20833587646484" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">aborted(bank-to-wallet)</text></g><g transform="translate(683.7916641235352 110.99999999999994) rotate(0 104.68333435058594 11.5)"><text x="104.68333435058594" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">aborting(wallet-to-bank)</text></g><g transform="translate(683.9833297729492 191.5) rotate(0 87.51667022705078 11.5)"><text x="87.51667022705078" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">aborted(after-wired)</text></g><g transform="translate(908.8125 194) rotate(0 102.375 11.5)"><text x="102.375" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">aborted(wallet-to-bank)</text></g><g transform="translate(698.1666641235352 282.5) rotate(0 123.33333587646484 11.5)"><text x="123.33333587646484" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">aborted(partially-withdrawn)</text></g><g stroke-linecap="round"><g transform="translate(907 124.99999999999994) rotate(0 17.218998830438863 27.38350120688684)"><path d="M0 0 C5.17 -0.17, 25.33 -11, 31 -1 C36.67 9, 33.5 49.83, 34 60 M0 0 C5.17 -0.17, 25.33 -11, 31 -1 C36.67 9, 33.5 49.83, 34 60" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g><g transform="translate(907 124.99999999999994) rotate(0 17.218998830438863 27.38350120688684)"><path d="M24.1 31.68 C27.78 42.21, 31.47 52.75, 34 60 M24.1 31.68 C27.26 40.72, 30.42 49.75, 34 60" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g><g transform="translate(907 124.99999999999994) rotate(0 17.218998830438863 27.38350120688684)"><path d="M44.62 31.94 C40.67 42.38, 36.72 52.81, 34 60 M44.62 31.94 C41.23 40.9, 37.84 49.85, 34 60" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(757 138.99999999999994) rotate(0 0.5 21)"><path d="M0 0 C0.17 7, 0.83 35, 1 42 M0 0 C0.17 7, 0.83 35, 1 42" stroke="#c92a2a" stroke-width="1" fill="none"></path></g><g transform="translate(757 138.99999999999994) rotate(0 0.5 21)"><path d="M-6.65 22.44 C-4.1 28.96, -1.55 35.47, 1 42 M-6.65 22.44 C-4.73 27.35, -2.81 32.26, 1 42" stroke="#c92a2a" stroke-width="1" fill="none"></path></g><g transform="translate(757 138.99999999999994) rotate(0 0.5 21)"><path d="M7.71 22.1 C5.48 28.73, 3.24 35.36, 1 42 M7.71 22.1 C6.03 27.09, 4.34 32.09, 1 42" stroke="#c92a2a" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(520 121.99999999999994) rotate(0 79 0.5)"><path d="M0 0 C26.33 0.17, 131.67 0.83, 158 1 M0 0 C26.33 0.17, 131.67 0.83, 158 1" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(520 121.99999999999994) rotate(0 79 0.5)"><path d="M129.74 11.08 C135.67 8.97, 141.59 6.86, 158 1 M129.74 11.08 C138.19 8.07, 146.63 5.06, 158 1" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(520 121.99999999999994) rotate(0 79 0.5)"><path d="M129.87 -9.44 C135.77 -7.25, 141.67 -5.06, 158 1 M129.87 -9.44 C138.28 -6.32, 146.68 -3.2, 158 1" stroke="#364fc7" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(565 29.999999999999943) rotate(0 57 0)"><path d="M0 0 C19 0, 95 0, 114 0 M0 0 C19 0, 95 0, 114 0" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(565 29.999999999999943) rotate(0 57 0)"><path d="M85.81 10.26 C94.86 6.97, 103.9 3.68, 114 0 M85.81 10.26 C92.38 7.87, 98.95 5.48, 114 0" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(565 29.999999999999943) rotate(0 57 0)"><path d="M85.81 -10.26 C94.86 -6.97, 103.9 -3.68, 114 0 M85.81 -10.26 C92.38 -7.87, 98.95 -5.48, 114 0" stroke="#364fc7" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(578 201.99999999999994) rotate(0 46.5 1.5)"><path d="M0 0 C15.5 0.5, 77.5 2.5, 93 3 M0 0 C15.5 0.5, 77.5 2.5, 93 3" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(578 201.99999999999994) rotate(0 46.5 1.5)"><path d="M64.49 12.35 C73.81 9.29, 83.13 6.24, 93 3 M64.49 12.35 C74.69 9, 84.88 5.66, 93 3" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(578 201.99999999999994) rotate(0 46.5 1.5)"><path d="M65.15 -8.16 C74.26 -4.52, 83.36 -0.87, 93 3 M65.15 -8.16 C75.11 -4.17, 85.07 -0.18, 93 3" stroke="#364fc7" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(534 291.99999999999994) rotate(0 79 -0.5)"><path d="M0 0 C26.33 -0.17, 131.67 -0.83, 158 -1 M0 0 C26.33 -0.17, 131.67 -0.83, 158 -1" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(534 291.99999999999994) rotate(0 79 -0.5)"><path d="M129.87 9.44 C140.43 5.52, 150.98 1.61, 158 -1 M129.87 9.44 C140.92 5.34, 151.97 1.24, 158 -1" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(534 291.99999999999994) rotate(0 79 -0.5)"><path d="M129.74 -11.08 C140.35 -7.3, 150.95 -3.52, 158 -1 M129.74 -11.08 C140.84 -7.12, 151.94 -3.16, 158 -1" stroke="#364fc7" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(726 396.99999999999994) rotate(0 17.998516892908526 -39.2735678019196)"><path d="M0 0 C5.67 -0.17, 28.67 13, 34 -1 C39.33 -15, 32.33 -70.17, 32 -84 M0 0 C5.67 -0.17, 28.67 13, 34 -1 C39.33 -15, 32.33 -70.17, 32 -84" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(726 396.99999999999994) rotate(0 17.998516892908526 -39.2735678019196)"><path d="M44.32 -56.65 C41 -64.02, 37.68 -71.39, 32 -84 M44.32 -56.65 C41.51 -62.87, 38.71 -69.1, 32 -84" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(726 396.99999999999994) rotate(0 17.998516892908526 -39.2735678019196)"><path d="M23.85 -55.13 C26.05 -62.91, 28.24 -70.69, 32 -84 M23.85 -55.13 C25.71 -61.7, 27.56 -68.28, 32 -84" stroke="#364fc7" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(565 513) rotate(0 132.5518314639386 -96.50620914312776)"><path d="M0 0 C40.33 -1.33, 199.17 25.67, 242 -8 C284.83 -41.67, 254.5 -169.67, 257 -202 M0 0 C40.33 -1.33, 199.17 25.67, 242 -8 C284.83 -41.67, 254.5 -169.67, 257 -202" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(565 513) rotate(0 132.5518314639386 -96.50620914312776)"><path d="M269.35 -174.66 C264.72 -184.92, 260.08 -195.18, 257 -202 M269.35 -174.66 C265.76 -182.61, 262.16 -190.57, 257 -202" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(565 513) rotate(0 132.5518314639386 -96.50620914312776)"><path d="M248.89 -173.12 C251.93 -183.96, 254.98 -194.79, 257 -202 M248.89 -173.12 C251.25 -181.52, 253.61 -189.92, 257 -202" stroke="#364fc7" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(301 441.99999999999994) rotate(0 300.91632424032133 12.106460231759684)"><path d="M0 0 C2.67 22.67, -80.33 115.67, 16 136 C112.33 156.33, 478.17 166.17, 578 122 C677.83 77.83, 608.83 -87.17, 615 -129 M0 0 C2.67 22.67, -80.33 115.67, 16 136 C112.33 156.33, 478.17 166.17, 578 122 C677.83 77.83, 608.83 -87.17, 615 -129" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(301 441.99999999999994) rotate(0 300.91632424032133 12.106460231759684)"><path d="M628.73 -102.32 C624.92 -109.73, 621.11 -117.13, 615 -129 M628.73 -102.32 C624.88 -109.79, 621.04 -117.26, 615 -129" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(301 441.99999999999994) rotate(0 300.91632424032133 12.106460231759684)"><path d="M608.37 -99.74 C610.21 -107.86, 612.05 -115.98, 615 -129 M608.37 -99.74 C610.22 -107.93, 612.08 -116.12, 615 -129" stroke="#364fc7" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(67.26666641235352 295) rotate(0 22.233333587646484 11.5)"><text x="22.233333587646484" y="0" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="text-before-edge">done</text></g><g stroke-linecap="round" transform="translate(56 292) rotate(0 33.5 14.5)"><path d="M0 0 C21.07 0, 42.14 0, 67 0 M0 0 C14.61 0, 29.22 0, 67 0 M67 0 C67 10.78, 67 21.57, 67 29 M67 0 C67 7.62, 67 15.23, 67 29 M67 29 C48.58 29, 30.17 29, 0 29 M67 29 C46.95 29, 26.89 29, 0 29 M0 29 C0 19.83, 0 10.65, 0 0 M0 29 C0 22.07, 0 15.13, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(682 10) rotate(0 110.5 17.5)"><path d="M0 0 C81.65 0, 163.3 0, 221 0 M0 0 C65.84 0, 131.68 0, 221 0 M221 0 C221 12.45, 221 24.91, 221 35 M221 0 C221 10.52, 221 21.04, 221 35 M221 35 C155.82 35, 90.65 35, 0 35 M221 35 C149 35, 76.99 35, 0 35 M0 35 C0 27.84, 0 20.69, 0 0 M0 35 C0 22.41, 0 9.83, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(678 188) rotate(0 93.5 15)"><path d="M0 0 C52.12 0, 104.23 0, 187 0 M0 0 C54.52 0, 109.04 0, 187 0 M187 0 C187 8.95, 187 17.9, 187 30 M187 0 C187 11.05, 187 22.1, 187 30 M187 30 C124.94 30, 62.88 30, 0 30 M187 30 C147.63 30, 108.27 30, 0 30 M0 30 C0 18.69, 0 7.39, 0 0 M0 30 C0 22.53, 0 15.05, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(905.6875 186) rotate(0 105.5 19.5)"><path d="M0 0 C74.72 0, 149.45 0, 211 0 M0 0 C64.15 0, 128.29 0, 211 0 M211 0 C211 8.42, 211 16.84, 211 39 M211 0 C211 13.08, 211 26.16, 211 39 M211 39 C138.63 39, 66.26 39, 0 39 M211 39 C139.7 39, 68.41 39, 0 39 M0 39 C0 30.58, 0 22.16, 0 0 M0 39 C0 29.88, 0 20.76, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(693 277) rotate(0 128.5 17)"><path d="M0 0 C74.43 0, 148.85 0, 257 0 M0 0 C96.48 0, 192.96 0, 257 0 M257 0 C257 13.14, 257 26.29, 257 34 M257 0 C257 8.22, 257 16.45, 257 34 M257 34 C161.04 34, 65.07 34, 0 34 M257 34 C155.04 34, 53.07 34, 0 34 M0 34 C0 22, 0 9.99, 0 0 M0 34 C0 26.27, 0 18.55, 0 0" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(279 292) rotate(0 -74 5)"><path d="M0 0 C-24.67 1.67, -123.33 8.33, -148 10 M0 0 C-24.67 1.67, -123.33 8.33, -148 10" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g><g transform="translate(279 292) rotate(0 -74 5)"><path d="M-120.57 -2.14 C-128.71 1.47, -136.86 5.07, -148 10 M-120.57 -2.14 C-126.23 0.37, -131.9 2.88, -148 10" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g><g transform="translate(279 292) rotate(0 -74 5)"><path d="M-119.18 18.34 C-127.74 15.86, -136.3 13.39, -148 10 M-119.18 18.34 C-125.14 16.61, -131.09 14.89, -148 10" stroke="#2b8a3e" stroke-width="1" fill="none"></path></g></g><mask></mask></svg> \ No newline at end of file
diff --git a/images/uptime-kuma-edit.png b/images/uptime-kuma-edit.png
new file mode 100644
index 00000000..23b85dad
--- /dev/null
+++ b/images/uptime-kuma-edit.png
Binary files differ
diff --git a/images/uptime-kuma-from-grafana.png b/images/uptime-kuma-from-grafana.png
new file mode 100644
index 00000000..c42b8660
--- /dev/null
+++ b/images/uptime-kuma-from-grafana.png
Binary files differ
diff --git a/images/wallet-confirm-withdraw.svg b/images/wallet-confirm-withdraw.svg
new file mode 100644
index 00000000..899728ae
--- /dev/null
+++ b/images/wallet-confirm-withdraw.svg
@@ -0,0 +1,16 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 645.5 1015.5" width="645.5" height="1015.5">
+ <!-- svg-source:excalidraw -->
+ <!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO2baVfiSFx1MDAxN8ffz6fIcd62TO2L79hUXFxQREV55jmeXHUwMDAwgUBCXHUwMDEyQ9ic0999KqBcdTAwMTAgYJrWXHUwMDE2p+V4VKqyVKp+91/31q3884em7Vx1MDAwNWPP2DvQ9oxRXbfbXHJfXHUwMDFm7n1cdTAwMGLLXHUwMDA3ht9ru46qQpPvPbfv1ydHmkHg9Vx1MDAwZf76a35Gqu52p2dcdTAwMTm20TWcoKeO+5/6rmn/TH5H7uNcdTAwMWL1QHdatjE5YVJcdTAwMTW5XHUwMDE1IculRdeZ3Fx1MDAxNlx1MDAwMkCQ5Fx1MDAxOMrZXHUwMDEx7V5O3S8wXHUwMDFhqrqp2z1jXlx1MDAxM1x1MDAxNu05h82K/mhJK1t8urox3Y7h30du22zbdjlcdTAwMTjb04fS62bfj9T2XHUwMDAy37WMSrtcdTAwMTGY4d2Xymfn9Vxc1Vx1MDAwNfOzfLffMlx1MDAxZKPXWzjH9fR6O1x1MDAxOE+fYlY67YVcdTAwMDNtXjKaXHUwMDFjIVFcblwiOitcdTAwMWNP+oWmOF1qQ9a1XT9sw59g8pm3oqbXrZZqitOYXHUwMDFkXHUwMDEz+LrT83RfXHLO/Ljh89MxhFJERj6zI0yj3TJcdTAwMDN1iMRCtVx1MDAwMMw+kVx1MDAwZTEmXHUwMDAzXHUwMDAwXHUwMDAxRoBcblxu5s1cZpvgXHUwMDE1XHUwMDFhXHUwMDEzXHUwMDE4/r/cgabue89cdTAwMWS111x1MDAwYr9Emlx1MDAxZrY8PyXp5fRJ3fdv2zCF1zNcdTAwMDWJelx1MDAxMkokT8xU//Ixa8G+mb0s92tiP91qmHn/XHUwMDEzMIVTgi8yXHUwMDA1hXxHoHCKk41AUbpCXHUwMDEw5MrEXHUwMDA1pfDXXHUwMDEzXHUwMDE0XHUwMDE4oyBcdTAwMGVcdTAwMWXI6Fp4kIBcdTAwMTBwSHBieDrp5tktyT9cdTAwMTVcdTAwMWac/qEv789rQ1bdeXggXHUwMDAzK/AgQd5TkDCKIYasalx1MDAwZZaAM0ZcdTAwMDF+XHUwMDE3YuZcdTAwMDPjOkG5/Vx1MDAxNPZccmZcdTAwMGKlh3q3bY9fJskpUiFK6lx1MDAwNlx1MDAxOd2xtMlTNlxyX2tcdTAwMTiB3rZ70S7pXHUwMDE5dtuZXFxz8eS03W6F7O3ZRnNcdTAwMTHKoK1m3Fl14Hp728tcIlx1MDAxNmxcdTAwMWTZXHUwMDE4XHUwMDEzIJRmJFdFNFx1MDAxZYlcdTAwMDZo3Vxic2h2XHUwMDAyUW0/le67O1x1MDAwZjZcdTAwMDWrM60yaZFC68muS6QjfXuyIWcpyUKZU8qBXHUwMDA0QyxcdTAwMDb0xalcdTAwMTbIXHUwMDE17lWrhZRcdTAwMDLGz7XPZeFjZlx1MDAxZYeD0dg0WVx0XFyOQXNUrKcv957rP0RQMV+LXHUwMDFkwUjNx5zQxNjlrnGt10Z6JX/bqTw1feT27d2fjClU2lx0I1xiLFx1MDAwMYhIXG5cdTAwMDNMn1x1MDAwZlx1MDAwMez9WCRsoSGArLKIYGrWlPB3RFx1MDAxNF5glERNhVJGJPtcdTAwMDNgjNNqKFI0vqNfke66roi0tWE7MMPwRrdjZVx1MDAxYvK1XfMmMj5l/DZbqY/S/ea5azHLs1x1MDAwNo1zt16bXy7e3l7m7Vx1MDAwNbIwh9E5e0ZB7LDjXHJcdTAwMTS/1Wz/0fa5ra/wXHUwMDAyPlwigqtRZzw6uC9RXHUwMDA3XHUwMDA0y6Uzx1G5LJJySZNEsqusO33bXiH20jZcdTAwMTSYithoXHUwMDBmRkxcdTAwMDGBJOz/XGKy8Vx1MDAxNrFcdTAwMDHkk9vi3SG7vW3rXHUwMDFkcthcdTAwMTlfX42veDKQXHUwMDExlqkl/5OQeJZ5jN/4xXJcdTAwMDKWXHUwMDAxxJxSXHUwMDE2iVx0I0FcdTAwMTDasCojXHUwMDEwUvJcdTAwMGaS+IpcdFkuZNLFXHUwMDAzzYKogztcdTAwMTY0XHUwMDExtjq7yvRZ/r5cIk/R5aDcwLend9XHXrNMtmaay1imyVx1MDAxN9PbMU2USkjJXHUwMDExjGM6XHUwMDEyMy4zLSlRXG6dLP5JyHSmkD3QbFx1MDAwNK1cdTAwMGW2LVx1MDAwNPHOXHUwMDEyfcFBoXfSsi46VXJcdTAwMDOD2khvutVtiaZcYkRjqVx1MDAxOdFcdTAwMTJ+XHUwMDExvVxy0YRcdTAwMGLGaTTsSybSUlx1MDAwMoJcdTAwMTB/S4ejqHeNXHUwMDAzLT+qm2q0XGat4NRTu4r0XHI+hFx1MDAwNZEp034uyF9XR5afXHUwMDA2eGukXHUwMDE5jEWagi+kt1x1MDAxMmnBVfiIXHUwMDA0imV6lfT56itcdTAwMTdUXGLI3pDpdFdcdTAwMWRcdTAwMTdcdTAwMWNoN+WcesTdwznZulx1MDAxZVx1MDAxNuv6jEjClFxmJE+gjdvSO9r3qmnPr41L18EhbFYvdlx1MDAwN71169WcKVx1MDAxM50vny2ur1x1MDAxMLLeXHUwMDA2MSPNOv+JZWuxkPVgMi6yZikqsfK2XHUwMDExJVx1MDAxMkBOli1cdTAwMDJcdTAwMDHOIYUwPlx1MDAwYvJcXKZK8zJzedFpl5npXHUwMDFlNa7cXHUwMDBi6Fx1MDAxN4boQ9f2XHUwMDEwW+9TcSwxZkzAxPBJViqdZrqw4qOzYlx1MDAxNz9cdTAwMTZcdTAwMDeeXdx9+Fx1MDAwNE5cdFwiXHUwMDAwllxiqnAqXCJPU/hoXG5AwoGSLoQphutcdTAwMTf3fpbFcFx1MDAxNXFGmVT3W0VcdTAwMTHSXHUwMDE0lFxmcEEmRypcdTAwMTdh1YWWqq3stZW9d0UxToYhSk16XHUwMDE3cUKVn1x1MDAxZbGzXHUwMDA1VZ6P4Wxlz/XG8ZJcdTAwMGLW9sUvzMnQtYvjysFcdTAwMDBIXHUwMDE52Fx1MDAwZmRcdTAwMWKv97PVo5wrx7etk0y/drJcdTAwMWZcXIPD3TegzeotVERcdTAwMDEweUFcdTAwMWK9m/28iZZjrGJcdTAwMWSqPJVXXGaocGtm3caZkb7tdkeg1KpegLtcdTAwMGbWcrFcdTAwMTI1v6CIIFKqIH4kUXNcdTAwMDXK40H15tJ0jkv57sNRPzvSdz9Rs6zlZFx0RZpCULyMPsL43Vh8XHUwMDFiLWdcXKhaRj9cdTAwMTTG30rN0TpcdTAwMTOSQvl3jIjkXHUwMDE5dlbbz1x1MDAxZlt2SVx1MDAxNo+vXHUwMDFl8oEvPLt+tPtcdTAwMTa0UcwpgilCP42YQ6hcXFig5uDXPHPr3LpcdTAwMDSPXHUwMDE39X1cdTAwMWSUee5hjMtew/hYNecrOar5XG4+VC5cdTAwMWVhOLljsY+rxlXFXHUwMDFiUL+Sz2TuLnnNxbe7z+JGNadq+Fx0i6j5bos5goBcYkkweU3M35XF30nMydrYliFAIWIwuTt0fnVcdTAwMGby11x1MDAxN8fnd4Nz+fTY4Sg38nbfgDaLOUMp+XnEXHUwMDFjXHUwMDAxXHTBYpIn3oBcdTAwMWPT9PtwRJ9aslghx/r9iXXrfPAyy9pcdTAwMTU+5Y4ub1x1MDAxOXuNxVx1MDAwMjTcgs6650f0yTJhqcdzJ3T3Wdws5oyn5OdcdTAwMTFzVS3DXHIh8jXH4l1Z/G+I+Vx1MDAxNGpvKNOnN96x5dxcdTAwMWTJ/dLJqWVVTlZTPjGKP837kIUkT/iI0ZW8mVx1MDAxMFx1MDAwMZSiq1x1MDAwM46g0sno5ne+geavNNCLXHUwMDFjI2Wn0eA0XCJ4dG1qk1xudebCtpVcdTAwMWbNXHUwMDAybaDo/qyTQydtcZx7aNIsyFQvS1x1MDAwM7BKUdzWO6VcdTAwMGJLXHUwMDAwcS7jXHUwMDEyh1TEXHUwMDEwXHUwMDE08eq+iFmXOORcXI094ihux1x1MDAxMlwi6+NcdTAwMWQuXHUwMDA041x1MDAxY9Mk8U7SxKFcdTAwMWRcdTAwMTi+o1x1MDAwN+2BYY+/aWO3r9V1R1OXcrVe+F9gtnta6Uqru1xyQ3N9zfVcZkfTro9cdTAwMGJl7axQPNX+dsJzTH1gaLpW01x1MDAxZKvttLS052ltp1x1MDAxN+i2bTTUJfRA6/U9z/WDnnZ1mNWEXHUwMDA00Yn6VycpXHTYYDqH9kMh91RcdTAwMTj2xdNcdTAwMTHP3e9XXHUwMDFhNMhvm3NnSmdjNkZh9pVz325cdTAwMWKJJFx1MDAwMtM4u5FrXHUwMDE3faFyuVx1MDAxMCRRc/tps+n1a1x1MDAxZDVcdTAwMDNcdTAwMWZopUpejXu6nFM/XHUwMDA0U/VV/fNZ8++rU9jsvVx1MDAxYVx1MDAwMpmKOn4gXHUwMDAxX2FOXHRfPDxcZq2j8ztGQFvW+589UFTO32dK4UDGJVDWXHUwMDAy498xmzvnpnuq81IlYId687pf22/lR1wi+8E5nPV70EOviXKeaPvMc1x1MDAwZce6OVx1MDAxYVp1/9pcdTAwMTjw6jBbv/H54Gn3WdxcdTAwMTgoMlx1MDAxNeAs5HB2O1CkXGZBqa7x2qLfu6L4X4pcdTAwMTPh9X32qGqWzvrGXcutXzL1sDfJPHxcIlx1MDAxNklSnMW49yTiZm7n3lx1MDAxYspZ/VxyfVx1MDAxNCg45pBSXHUwMDE093JccpQrzsv83VUslWNcdTAwMTh5V/in3ZRz3TKU5+1cdTAwMWJa4Gr9nvpjXHUwMDFhypP3QzdAe/ZhvmmuKvWH7Wn1307XdYyxNlSDoDluoOm+r4JcdTAwMDPlzk9DgWHo01x1MDAwN1x1MDAxZrljdqP33qlcdTAwMWTfyv6ooVx1MDAxZlx1MDAwZfRcdTAwMGJqV+C41o9cdHzXLZ9AxFNLXHUwMDFlPGNxXHUwMDFlPIUxwa+InvxlXHUwMDFma+yDc07C7UBx6yXrd1x1MDAxMYV7XHUwMDBiXHUwMDA1QeQnzGNcdTAwMDM210FcdTAwMTftXHUwMDFm2/nSWdlr2KDLhU7TyYK+yG6T6auKILWKXHUwMDBij4v3yFx1MDAwZrDym8Z7XHUwMDEwIMhcdTAwMDSFq9HdpHKDj6hmNZFsw3BCLd1iazVeuMhPh3ZyXHUwMDAzwEG2g24ydXZxWfQy+/jee1x1MDAwMFYuXHUwMDExwJitrFqERTFcdTAwMWVcdTAwMDGKcVxivlx1MDAxNi1cdTAwMTK9bStcdTAwMTFYeM18XHUwMDBl8YblvslcdTAwMWJgXHUwMDE4kDeEOHBcdTAwMGZ2YHHij2dXfk/3vHKgXHUwMDA3Yd2U571B21x1MDAxOGZWsfizOfmEXHUwMDBl8fc/vv9cdTAwMGIhXG42wCJ9<!-- payload-end -->
+ <defs>
+ <style>
+ @font-face {
+ font-family: "Virgil";
+ src: url("https://excalidraw.com/Virgil.woff2");
+ }
+ @font-face {
+ font-family: "Cascadia";
+ src: url("https://excalidraw.com/Cascadia.woff2");
+ }
+ </style>
+ </defs>
+ <rect x="0" y="0" width="645.5" height="1015.5" fill="#ffffff"></rect><g stroke-linecap="round" transform="translate(10 66.75) rotate(0 311.25 469.375)"><path d="M0.1 -0.43 C191.81 -1, 384.73 -0.48, 622.99 0.04 M0.24 0.31 C237.23 1.21, 474.12 1.74, 622.31 0.32 M622.81 0.69 C619.82 265.46, 618.57 531.76, 622.65 939.19 M622.53 0.18 C625.38 220.28, 625.13 441.42, 622.35 938.57 M622.74 938.73 C459.11 938.32, 294.82 938.61, -0.09 938.67 M622.29 938.85 C380.68 940.76, 139.59 940.06, 0.15 938.78 M0.56 938.83 C-0.16 733.07, 0.31 526.84, -0.04 -0.27 M-0.24 938.63 C-1.96 647.7, -2.08 356.96, -0.3 0.05" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(11.75 10) rotate(0 311.875 27.5)"><path d="M-0.43 -0.54 C226.54 -0.29, 453.87 0.19, 623.79 0.65 M0.31 0.19 C148.17 -1.46, 297.24 -1.68, 624.07 -0.07 M625.48 1.56 C623.23 10.11, 625.05 23.69, 624.84 53.7 M624.2 0.53 C623.31 20.31, 624.81 40.45, 623.3 54.63 M623.73 55.12 C400.92 55.1, 178.89 55.67, -0.08 55.7 M623.85 54.74 C383.85 53.9, 142.86 53.83, 0.03 54.68 M0.19 54.52 C0.68 39.24, -0.45 22, -0.67 0.2 M-0.3 54.31 C0.38 35.05, 1.01 16.31, 0.12 -0.68" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(78.75 105.75) rotate(0 164.5 20.5)"><text x="0" y="32" font-family="Helvetica, Segoe UI Emoji" font-size="36px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Bank transfer details</text></g><g stroke-linecap="round" transform="translate(420 929.25) rotate(0 88.48214285714312 24.375)"><path d="M1.19 1.55 C68.32 -0.77, 134.91 1.85, 176.01 1.6 M0.39 0.86 C50.84 0.56, 99.35 1.47, 177.15 0.55 M177.1 0.91 C178.37 10.19, 177.1 24.64, 176.22 47.86 M177.27 -0.03 C177.39 12.18, 176.42 25.35, 176.85 48.65 M175.91 49.23 C106.99 51.87, 40.71 48.37, 0.75 48.88 M177.66 48.85 C137.93 47.4, 99.73 46.84, -0.05 48.41 M-1.2 48.14 C-1.6 33.39, -2.18 19.55, -1.51 0.24 M-0.21 47.95 C-0.76 37.33, -0.29 26.84, -0.34 0.86" stroke="#c92a2a" stroke-width="1" fill="none"></path></g><g transform="translate(432.58928571428623 945.3035714285706) rotate(0 73.357142857143 10.678571428571445)"><text x="0" y="17.357142857142897" font-family="Helvetica, Segoe UI Emoji" font-size="18.57142857142862px" fill="#c92a2a" text-anchor="start" style="white-space: pre;" direction="ltr">cancel withdrawal</text></g><g transform="translate(77.875 192.75) rotate(0 52 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Please wire</text></g><g transform="translate(157.625 262.75) rotate(0 89.5 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">IBAN: k12j3jk1h23kj</text></g><g transform="translate(157.625 300.75) rotate(0 74.5 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">BIC: l21kj3lk213j</text></g><g transform="translate(157.625 341.25) rotate(0 95.5 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Name: Exchange Inc.</text></g><g transform="translate(157.625 382.25) rotate(0 75 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Amount: USD 10</text></g><g stroke-linecap="round" transform="translate(94.12500000000023 261) rotate(0 19.374999999999886 13.296568627450881)"><path d="M0.2 1.6 C6.8 -0.4, 15.21 2.08, 40.58 0.44 M0.54 -0.57 C14.67 0.42, 29.71 0.1, 39.41 0.7 M39.39 0.92 C36.83 9.01, 39.01 14.69, 39.87 25.7 M39.27 0.69 C39.52 11.43, 39.74 20.45, 38.03 26.49 M38.22 25.75 C22.92 25.11, 8.14 27.35, -1.75 26.82 M39.03 26.1 C27.25 26.21, 14.83 26.88, 0.93 26.14 M-0.74 24.9 C0.74 19.34, 1.19 11.08, 0.05 -0.27 M0.7 25.62 C1.09 16.81, -0.57 8.72, 0.31 -0.89" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(101.72303921568687 266.01470588235316) rotate(0 12.156862745097897 7.598039215686214)"><text x="0" y="10.196078431372422" font-family="Virgil, Segoe UI Emoji" font-size="12.15686274509794px" fill="#364fc7" text-anchor="start" style="white-space: pre;" direction="ltr">copy</text></g><g stroke-linecap="round" transform="translate(94.12500000000023 301.2034313725492) rotate(0 19.374999999999886 13.296568627450881)"><path d="M-1.8 -0.14 C12.37 1.47, 28.62 1.27, 37.36 -1.73 M0.39 1 C13.1 -0.86, 25.79 0.16, 37.85 -0.43 M38.24 1.81 C37.08 7.65, 38.9 17.94, 40.18 24.78 M39.45 0.2 C39.01 7.37, 39.26 12.39, 38.56 26.23 M39.88 27.03 C24.89 26.77, 10.63 25.1, 1.58 27.03 M39.75 27.54 C28.74 27.01, 18.79 27.01, 0.77 27.26 M1.89 28.26 C0.17 21.47, -0.68 14.05, 0.4 -0.35 M0.39 25.68 C0.67 15.44, 0.45 5.81, 0.11 0.6" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(101.72303921568641 306.21813725490233) rotate(0 12.156862745097897 7.598039215686214)"><text x="0" y="10.196078431372422" font-family="Virgil, Segoe UI Emoji" font-size="12.15686274509794px" fill="#364fc7" text-anchor="start" style="white-space: pre;" direction="ltr">copy</text></g><g stroke-linecap="round" transform="translate(94.12500000000023 342.4534313725492) rotate(0 19.374999999999886 13.296568627450881)"><path d="M-0.38 -0.73 C16.13 0.66, 29.47 1.3, 39.19 -0.71 M0.79 0.22 C12.09 0.74, 24.2 1.24, 39.69 0.34 M40.29 1.33 C37.37 11.2, 38.46 21.39, 40.42 26.95 M38.95 -0.18 C39.64 9.14, 37.8 18.36, 37.83 27.31 M38.96 27.79 C28.84 25.41, 21.91 27.74, -1.04 28.06 M38.26 26.44 C28 27.11, 17.37 27.04, -0.97 26.55 M-0.09 25.8 C-0.26 15.61, -1.09 7.69, -0.49 0.26 M-0.4 27.52 C0.35 19.06, 0.53 12.64, -0.83 0.34" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(101.72303921568641 347.46813725490233) rotate(0 12.156862745097897 7.598039215686185)"><text x="0" y="10.196078431372422" font-family="Virgil, Segoe UI Emoji" font-size="12.15686274509794px" fill="#364fc7" text-anchor="start" style="white-space: pre;" direction="ltr">copy</text></g><g stroke-linecap="round" transform="translate(94.12500000000023 383.9534313725492) rotate(0 19.374999999999886 13.296568627450881)"><path d="M-0.49 -0.78 C15.26 -0.5, 31.64 0.17, 36.97 0.79 M0.5 0.28 C8.18 0.84, 15.8 -0.41, 39.54 0.52 M38.8 1.45 C37.97 6.29, 39.23 13.66, 39.55 26.93 M38.41 -0.99 C38.69 5.01, 38.56 10.33, 38.16 27.15 M40.58 24.93 C27.27 28.29, 18.6 25.21, 1.55 26.35 M38.83 27.42 C29.93 26.92, 21.21 25.9, -0.76 26.99 M1.87 26.4 C-1.77 17.07, 1.42 10.3, 1.88 0.91 M0.53 26.14 C-0.51 17.99, -0.02 10.03, 0.66 0.83" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(101.72303921568641 388.96813725490233) rotate(0 12.156862745097897 7.598039215686185)"><text x="0" y="10.196078431372422" font-family="Virgil, Segoe UI Emoji" font-size="12.15686274509794px" fill="#364fc7" text-anchor="start" style="white-space: pre;" direction="ltr">copy</text></g><g stroke-linecap="round" transform="translate(159.125 690) rotate(0 151.25 108.125)"><path d="M-0.59 -0.65 C83.72 -0.73, 165.78 1.76, 301.11 -0.16 M-0.3 0.73 C68.13 1.91, 137.74 1.33, 302.4 0.68 M303.7 1.55 C302.89 46.8, 303.22 91.56, 301.87 215.05 M302.76 -0.38 C303.92 68.39, 303.93 138.49, 303.34 215.92 M301.06 217.22 C191.77 218.63, 83.96 217.97, 1.38 217.12 M303.01 216.46 C187.06 215.84, 72.43 214.73, -0.58 215.7 M-0.49 214.79 C2.29 161.3, 1.47 109.67, 1.42 -0.99 M-0.83 215.67 C0.89 145.95, -0.16 76.71, -0.78 0.74" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(42.125 600.25) rotate(0 292.5 22.5)"><text x="0" y="17.5" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Alternatively, you can also scan this QR code or open THIS LINK </text><text x="0" y="40" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">you have a banking App installed that supports RFC 8905</text></g><g transform="translate(157.625 423.75) rotate(0 180 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">subject: QWE123ASDASD435QWEASD</text></g><g stroke-linecap="round" transform="translate(94.12500000000023 428.2034313725492) rotate(0 19.374999999999886 13.296568627450881)"><path d="M-0.38 1.12 C8.3 2.21, 20.85 0.78, 38.1 -1.47 M-0.14 0.95 C8.36 -0.35, 17.46 -0.48, 38.72 -0.75 M40.24 -0.22 C38.82 5.85, 37.43 11.71, 36.87 24.97 M37.87 -0.72 C38.61 10.14, 39.32 21.4, 39.72 26.66 M40.72 26.3 C28.27 25.29, 15.24 27.74, 1.91 25.32 M38.39 27.31 C25.46 26.86, 10.75 27.7, -0.74 26.71 M-0.24 28.49 C1.24 17.12, 1.53 5.62, 2 -0.76 M-0.96 25.67 C-0.53 18.42, -0.61 10.78, 0.5 0.34" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(101.72303921568641 433.21813725490233) rotate(0 12.156862745097897 7.598039215686185)"><text x="0" y="10.196078431372422" font-family="Virgil, Segoe UI Emoji" font-size="12.15686274509794px" fill="#364fc7" text-anchor="start" style="white-space: pre;" direction="ltr">copy</text></g><g transform="translate(65.875 504.25) rotate(0 226.5 22.5)"><text x="0" y="17.5" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#e67700" text-anchor="start" style="white-space: pre;" direction="ltr">Make sure to use the correct subject, otherwise the</text><text x="0" y="40" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#e67700" text-anchor="start" style="white-space: pre;" direction="ltr">money will not arrive in this wallet.</text></g><g stroke-linecap="round" transform="translate(45.375 487.75) rotate(0 257.5 43.75)"><path d="M0.34 0.72 C200.37 1.93, 399 2.26, 514.51 -0.13 M0.03 -0.22 C123.26 0.72, 246 1.36, 514.88 0.35 M514.83 -1.24 C515.78 20.87, 515.26 40.81, 513.13 85.59 M514.86 -0.18 C515.13 22.54, 514.29 45.85, 514.42 87.17 M515.15 87.04 C350.04 88.8, 185.58 89.06, 0.52 86.83 M514.84 87.7 C403.52 86.46, 292.49 86.9, -0.2 87.35 M0.93 86.82 C-0.35 56.29, -1.91 25.03, -1.42 -1.99 M-0.54 87.01 C0.32 55.97, -0.86 25.45, 0.04 -0.52" stroke="#e67700" stroke-width="1" fill="none"></path></g><g transform="translate(198.875 191.5) rotate(0 35 12)"><text x="0" y="19" font-family="Cascadia, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">USD 10</text></g><g transform="translate(287.625 190.25) rotate(0 11.5 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">to:</text></g></svg> \ No newline at end of file
diff --git a/images/wallet-mobile-overview.svg b/images/wallet-mobile-overview.svg
new file mode 100644
index 00000000..5f41659b
--- /dev/null
+++ b/images/wallet-mobile-overview.svg
@@ -0,0 +1,103 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1190.625 647.5" width="1190.625" height="647.5">
+ <!-- svg-source:excalidraw -->
+
+ <defs>
+ <style>
+ @font-face {
+ font-family: "Virgil";
+ src: url("https://excalidraw.com/Virgil.woff2");
+ }
+ @font-face {
+ font-family: "Cascadia";
+ src: url("https://excalidraw.com/Cascadia.woff2");
+ }
+ </style>
+ </defs>
+ <rect x="0" y="0" width="1190.625" height="647.5" fill="#ffffff"></rect>
+ <g stroke-linecap="round" transform="translate(10 10) rotate(0 433.125 313.75)">
+ <path d="M0.15 -0.75 C280.81 -1.32, 560.96 -0.77, 865.84 0.07 M-0.13 0.07 C216.66 2.23, 432.34 1.9, 866.24 0.31 M866.35 -0.29 C865.75 141.88, 865.41 283.41, 865.87 628.1 M866.59 -0.15 C866.57 194.82, 866.86 388.81, 866.44 627.67 M866.04 626.84 C593.8 625.52, 322.18 624.91, -0.79 627.56 M866.3 627.9 C664.27 625.26, 462.26 625.16, -0.11 627.57 M-0.45 627.39 C-2.5 418.01, -2.68 208, 0.23 -0.21 M-0.06 627.34 C0.58 426.24, 0.45 225.45, 0.23 -0.27" stroke="#000000" stroke-width="1" fill="none"></path>
+ </g>
+ <g stroke-linecap="round" transform="translate(272.375 151.75) rotate(0 154.875 148)">
+ <path d="M0.26 1.43 C101.9 -0.6, 205.03 -1.56, 309.89 0.7 M-0.48 -0.28 C68.23 1.47, 135.67 1.08, 310.07 0.6 M310.69 0.76 C308.01 75.39, 307.82 151.52, 308.65 296.47 M310.19 -0.01 C307.79 95.24, 307.74 190.28, 309.85 295.66 M309.75 295.55 C245.1 293.74, 181.38 292.61, 1.2 296.97 M309.1 296.38 C190.11 296.75, 69.6 297.2, 0.22 295.93 M-0.53 295.42 C2 207.16, 1.39 117.05, -1.37 -0.64 M-0.05 295.88 C-0.31 226.22, 0.9 156.92, 0.33 0.27" stroke="#000000" stroke-width="1" fill="none"></path>
+ </g>
+ <g stroke-linecap="round" transform="translate(36.625 147) rotate(0 105 151)">
+ <path d="M-0.72 -0.1 C68.83 -0.69, 140.24 0.01, 210.59 -1.5 M-0.17 -0.16 C43.48 1.05, 86.21 1.19, 210.57 0.58 M210.63 0.08 C209.93 105.13, 210.15 208.37, 209.12 302.44 M209.3 0.08 C212.33 95.38, 211.41 190.12, 209.67 301.85 M208.37 300.54 C160.16 303.18, 114.89 303.07, 0.48 303.5 M209.46 302.41 C150.83 302.73, 93.63 302, 0.27 302.86 M-0.9 301.87 C0.71 231.93, 1.75 158.31, -0.45 0.41 M-0.42 301.98 C-1.94 191.93, -1.85 82.62, -0.09 -0.62" stroke="#000000" stroke-width="1" fill="none"></path>
+ </g>
+ <g stroke-linecap="round" transform="translate(49.375 34.75) rotate(0 270 51)">
+ <path d="M-0.03 -0.2 C204.47 1.13, 409.77 1.14, 539.32 -0.47 M0.05 0.26 C187.08 0.34, 374.58 0.77, 539.94 -0.06 M538.35 -0.86 C538.73 36.84, 541 72.79, 540.45 103.97 M539.44 -0.48 C540.3 30.38, 540.23 59.33, 539.1 102.57 M539.71 102.5 C420.92 100.6, 302.28 100.54, 0.5 102.71 M539.91 101.81 C358.02 99.85, 176.84 99.89, 0.12 101.78 M-1.2 102.2 C-0.36 61.46, -1.01 20.24, 1.47 -0.64 M-0.24 102.88 C-0.3 64.62, -0.12 25.79, -1 0.06" stroke="#000000" stroke-width="1" fill="none"></path>
+ </g>
+ <g stroke-linecap="round" transform="translate(598.625 169.5) rotate(0 125.5 132)">
+ <path d="M-0.91 -0.78 C71.81 0.78, 144.15 -0.04, 249.54 0.93 M-0.29 0.51 C55.19 1.81, 110.83 1.76, 251.51 0.72 M250.63 -0.76 C250.96 87.25, 252.54 176.17, 251.48 263.11 M250.52 0.08 C251.68 103.86, 251.42 207.46, 251.58 263.74 M250.61 265.44 C157.64 267.2, 64.04 266.1, -1.62 264.1 M251.38 264.76 C161.63 263.52, 70.94 263.51, 0.35 264.16 M-1.04 265.34 C2.31 190.08, 1.15 115.07, 0.84 0.84 M0.27 264.27 C-1.34 179.25, -1.01 94.2, 0.45 0.04" stroke="#000000" stroke-width="1" fill="none"></path>
+ </g>
+ <g stroke-linecap="round" transform="translate(267.375 456.5) rotate(0 144.25 63.75)">
+ <path d="M0.48 1.16 C114.8 -1.77, 226.6 -1.82, 289.37 0.19 M0.37 0.57 C70.6 -1.46, 142.5 -1.87, 288.39 -0.41 M289.98 1.65 C287.67 52.38, 288.73 101.99, 288.96 128.65 M288.32 0.63 C289.17 26.61, 289.5 51.51, 288.5 128.17 M289.65 128.81 C189.01 126.88, 89.27 126.99, -0.33 127.8 M288.44 126.9 C220.2 127.93, 153.44 128.19, 0.38 127.81 M1.29 125.65 C0.56 86.14, -2.12 46.84, -1.25 -0.95 M-0.29 126.52 C-0.49 77.56, -1.63 29.12, -0.87 0.1" stroke="#000000" stroke-width="1" fill="none"></path>
+ </g>
+ <g transform="translate(58.625 208.5) rotate(0 69 80.5)">
+ <text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Select currency</text>
+ <text x="0" y="41" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">EUR</text>
+ <text x="0" y="64" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">CHF</text>
+ <text x="0" y="87" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">USD</text>
+ <text x="0" y="110" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">BTC</text>
+ <text x="0" y="133" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"></text>
+ <text x="0" y="156" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">[Withdraw]</text>
+ </g>
+ <g transform="translate(293.875 181.75) rotate(0 86.5 80.5)">
+ <text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Pending operations</text>
+ <text x="0" y="41" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Balance in selected</text>
+ <text x="0" y="64" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">currency</text>
+ <text x="0" y="87" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"></text>
+ <text x="0" y="110" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"></text>
+ <text x="0" y="133" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"></text>
+ <text x="0" y="156" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"></text>
+ </g>
+ <g transform="translate(326.875 492) rotate(0 56.5 11.5)">
+ <text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Send money</text>
+ </g>
+ <g transform="translate(628.625 187.5) rotate(0 84 23)">
+ <text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Transaction history</text>
+ <text x="0" y="41" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr"></text>
+ </g>
+ <g stroke-linecap="round" transform="translate(936.625 169.75) rotate(0 122 126.5)">
+ <path d="M0.91 -0.91 C52.69 -0.51, 104.5 -1.1, 244.72 -1.48 M-0.67 0.09 C92.15 2.03, 184.38 1.6, 244.79 -0.04 M244.06 0.75 C245.53 88.2, 243.77 173.71, 245.37 254.62 M243.79 -0.33 C245.21 62.95, 244.21 125.42, 243.2 252.8 M244.97 253.34 C159.06 253.7, 71.75 253.14, -0.26 254.22 M244.41 252.94 C178.4 254.73, 114.81 254.17, -0.61 253.76 M1.54 254.04 C2.62 171.09, 2.56 88.97, -0.74 1.1 M-0.07 253.07 C1.05 153.82, 1.14 54.8, 0.03 0.62" stroke="#000000" stroke-width="1" fill="none"></path>
+ </g>
+ <g transform="translate(967.625 195.75) rotate(0 84 11.5)">
+ <text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Transaction details</text>
+ </g>
+ <g transform="translate(298.875 383.75) rotate(0 0.00004999999998744897 0.00004999999998744897)" stroke="none">
+ <path fill="#000000" d="M 1.57,-1.57 Q 1.57,-1.57 1.77,-1.27 1.98,-0.98 2.09,-0.64 2.20,-0.29 2.19,0.05 2.18,0.41 2.05,0.75 1.93,1.09 1.70,1.37 1.48,1.65 1.18,1.84 0.87,2.04 0.52,2.12 0.18,2.21 -0.17,2.18 -0.53,2.15 -0.86,2.01 -1.19,1.87 -1.46,1.63 -1.73,1.39 -1.90,1.07 -2.08,0.76 -2.15,0.41 -2.21,0.05 -2.17,-0.29 -2.12,-0.65 -1.96,-0.97 -1.80,-1.29 -1.54,-1.54 -1.29,-1.80 -0.97,-1.96 -0.65,-2.12 -0.29,-2.17 0.06,-2.21 0.41,-2.15 0.76,-2.08 1.07,-1.90 1.39,-1.73 1.63,-1.46 1.87,-1.19 2.01,-0.86 2.15,-0.53 2.18,-0.17 2.21,0.18 2.12,0.52 2.03,0.87 1.84,1.18 1.65,1.48 1.37,1.70 1.09,1.93 0.75,2.05 0.41,2.18 0.05,2.19 -0.30,2.20 -0.64,2.09 -0.98,1.98 -1.27,1.77 -1.57,1.56 -1.57,1.57 -1.57,1.57 -1.73,1.35 -1.90,1.14 -2.01,0.90 -2.12,0.66 -2.16,0.39 -2.21,0.13 -2.20,-0.13 -2.18,-0.40 -2.10,-0.65 -2.02,-0.91 -1.88,-1.14 -1.74,-1.36 -1.55,-1.55 -1.36,-1.74 -1.14,-1.88 -0.91,-2.02 -0.65,-2.10 -0.40,-2.18 -0.13,-2.20 0.13,-2.21 0.39,-2.16 0.66,-2.12 0.90,-2.01 1.14,-1.90 1.35,-1.73 1.57,-1.57 1.57,-1.57 L 1.57,-1.57 Z"></path>
+ </g>
+ <g transform="translate(310.875 354.75) rotate(0 40 11.5)">
+ <text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">[Deposit]</text>
+ </g>
+ <g transform="translate(757.625 250.5) rotate(0 35 11.5)">
+ <text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">[Delete]</text>
+ </g>
+ <g transform="translate(1042.625 261.75) rotate(0 35 11.5)">
+ <text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">[Forget]</text>
+ </g>
+ <g transform="translate(340 95.25) rotate(0 71 11.5)">
+ <text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">amount, subject</text>
+ </g>
+ <g transform="translate(81.25 51.5) rotate(0 58.5 11.5)">
+ <text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Send Invoice</text>
+ </g>
+ <g transform="translate(482.875 167.75) rotate(0 15 12.5)">
+ <text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">[?]</text>
+ </g>
+ <g stroke-linecap="round">
+ <g transform="translate(300 62.5) rotate(0 0.4346650920482489 32.930345324641095)">
+ <path d="M1.17 -0.33 C1.22 10.67, -0.64 55.15, -0.73 66.43 M0.33 -1.55 C0.85 9.53, 1.63 55.71, 1.6 67.41" stroke="#000000" stroke-width="1" fill="none"></path>
+ </g>
+ </g>
+ <g transform="translate(137.5 91.5) rotate(0 26 11.5)">
+ <text x="0" y="18" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">target</text>
+ </g>
+ <g stroke-linecap="round" transform="translate(516.25 398.75) rotate(0 18.75 19.375)">
+ <path d="M12.92 1.01 C16.48 -0.48, 22.52 -0.81, 26.16 0.83 C29.8 2.47, 32.97 6.89, 34.75 10.85 C36.52 14.81, 37.63 20.49, 36.81 24.59 C35.99 28.68, 32.97 33.11, 29.85 35.42 C26.73 37.74, 22.08 38.7, 18.1 38.48 C14.12 38.25, 8.92 36.89, 5.96 34.05 C3 31.21, 0.83 25.65, 0.34 21.46 C-0.14 17.26, 0.68 12.58, 3.06 8.89 C5.44 5.2, 12.3 0.79, 14.62 -0.67 C16.95 -2.13, 16.64 -0.38, 16.99 0.13 M16.61 -0.86 C20.08 -1.86, 24.07 -0.08, 27.27 2.37 C30.47 4.81, 34.22 10.05, 35.83 13.82 C37.43 17.6, 38.35 21.05, 36.9 25.03 C35.45 29.01, 30.68 35.52, 27.16 37.72 C23.63 39.92, 19.78 39.32, 15.77 38.25 C11.75 37.17, 5.65 34.69, 3.05 31.26 C0.46 27.83, -0.02 21.77, 0.2 17.64 C0.42 13.52, 1.52 9.63, 4.36 6.52 C7.2 3.41, 15.12 0.13, 17.26 -1 C19.41 -2.13, 17.2 -0.78, 17.2 -0.25" stroke="#000000" stroke-width="1" fill="none"></path>
+ </g>
+ <g stroke-linecap="round" transform="translate(192 397.625) rotate(0 18.75 19.375)">
+ <path d="M17.85 0.94 C21.44 0.46, 25.57 1.47, 28.86 3.74 C32.14 6.01, 36.59 10.58, 37.58 14.55 C38.57 18.53, 36.72 23.73, 34.8 27.61 C32.87 31.5, 29.45 35.99, 26.03 37.85 C22.62 39.72, 18.13 40.18, 14.29 38.81 C10.45 37.43, 5.33 33.05, 2.99 29.61 C0.64 26.17, -0.19 22.35, 0.2 18.17 C0.6 13.99, 2.27 7.39, 5.37 4.5 C8.48 1.61, 16.38 1.42, 18.84 0.81 C21.29 0.2, 20.1 0.81, 20.13 0.83 M12.52 -0.21 C16.27 -1.92, 22.65 -1.55, 26.39 0.39 C30.13 2.34, 33.29 7.72, 34.97 11.45 C36.64 15.19, 37.14 18.79, 36.44 22.81 C35.74 26.82, 33.76 32.77, 30.76 35.52 C27.76 38.27, 22.47 39.49, 18.43 39.31 C14.39 39.12, 9.35 37.3, 6.53 34.41 C3.7 31.53, 2.23 26.49, 1.47 22.01 C0.71 17.53, -0.16 11.26, 1.96 7.53 C4.09 3.8, 12.15 0.47, 14.23 -0.38 C16.3 -1.23, 14.25 1.84, 14.41 2.44" stroke="#000000" stroke-width="1" fill="none"></path>
+ </g>
+</svg>
+
+ \ No newline at end of file
diff --git a/images/wallet-start-manual-withdraw.svg b/images/wallet-start-manual-withdraw.svg
new file mode 100644
index 00000000..708b4cdb
--- /dev/null
+++ b/images/wallet-start-manual-withdraw.svg
@@ -0,0 +1,16 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 649.25 613" width="649.25" height="613">
+ <!-- svg-source:excalidraw -->
+ <!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO2aWXPaOFx1MDAxY8Df+ylcdTAwMTj2taW6JfeNJqXlyEXClnRnp+PYXHUwMDAym/igtrnS6Xdf2STYYENdSnazMzCZJNaBZOmn/6nvryqVarRcdTAwMTjL6rtKVc5cct2xzUCfVV/H5VNcdTAwMTmEtu+pKpQ8h/4kMJKWVlx1MDAxNI3Dd2/fpj1qhu8ue0lHutKLQtXuL/VcXKl8T35nxlx0pFx1MDAxMene0JFJh6QqXHUwMDFkXG5cIr5Zeu57ybBcdTAwMWFcIphcdTAwMGLG8KqBXHUwMDFknqrhXCJpqtqB7oQyrYmLqro+ciZcdTAwMWW6gNc9+G0442cyYN101IHtONfRwlm+k25YkyAzpzBcbvx7+dk2Iyue10b5ql/oq1x1MDAxNUh7XHUwMDA1/mRoeTJcZtf6+GPdsKNFXFxcdTAwMDbAqnS5XGLvKmnJXFw9YU5Xz3FcdTAwMGZEUY1ujH7iO35cdTAwMTCP/lx1MDAwN0g+6fh3unE/VJPwzFWbKNC9cKxcdTAwMDdqV9J2s8f3Yohnvt2S9tCKVDHF2eJQJktcZjHhkKk9QKuaeKhx00x2++/NJbL0YPy4XHUwMDE01TB+yEwznuGHJSpP3ZO6XHUwMDFmr/eBhpNt0CDGXHUwMDExwFx1MDAxNGmloWmF0Fx1MDAxYlx1MDAxYi1cXO9p/S/NXHUwMDFlnUze3338XHUwMDFmQFNbx1x1MDAwNmr8XHUwMDE5oVx1MDAxMTVeRE1cdTAwMWVcdTAwMTmqcUSpwPjfQ2a5je2BOb+zvzgmXHUwMDFkTCdu53YyMCaZbdzBVbyehIK11cSU1Vx1MDAxMM0tXHUwMDA0XHUwMDEyqPD0ZEvzXHUwMDFidqjt+K9R3Hcnn9jgXGJcIo0xnp7N9EhraLPw6URzJYFcYtFwivf2XHUwMDEznWfGmzjOXHUwMDBlarri/JN9XHUwMDFkdq6QNVx1MDAxZVx1MDAxOTfWXGL1vmp5alwiOY82gcG1XHLBjVx1MDAxMclcdTAwMDHDWZ5cdTAwMTaEj6z8lFx1MDAxNUaxgIQzWMCK2GoyXGJcdTAwMDFcdTAwMDBcdTAwMTNcdTAwMWPCvVlJtz7ecjU/Y1x1MDAxMqiVNVx1MDAxNpml9b3o2n5ItFxyWCtt6K7tLJ5cZqjV19RcdTAwMWR7XHUwMDE4z7vqyEG0ps9cIltcdTAwMTlUq+rIz4o/PZSO7cnk4OwgeN41Qlx1MDAxOTVbJ99cdTAwMWGyaTeaI3tuXHL2lntEXHUwMDAzOYYxQDWiZT55pMlR/JVcdTAwMTB/QGNcdTAwMTCjjNLMWNxgq0VDiOpcdTAwMDRZXHUwMDE5g+aXxV87asvTL2bvZEIuKVuMOmdh0Chcclx1MDAwZuNrSnKpN9cshSeEaLHRucvKOVKTbLDggkIqYFx1MDAxMTRcdTAwMTBsVZpqXHUwMDA2XHUwMDEwXHUwMDAxRNmzaE23fv+V9q3ueHo1PNV7oze9Py+uy2lNuElcZqF5rSmOWnM/XHUwMDExg4hQnlx1MDAwMWGFtJDttFCgiTJudkmdKeeGpTZJvlSdiU5cdTAwMWEtfNd5oIEwyc2cXnwx5Hkpflx1MDAxOdpwuyiAtby8g+hI8F5cdTAwMDRrXHUwMDFjY1x1MDAwNDgvXHUwMDA0mImtdlx1MDAxZqGMaMpLOFx1MDAxY8OmdP1apDsyqHkyeqkkXHUwMDFicsE7/WFjMGjctuyW8/H8ejQqRTJcdTAwMTdrXHUwMDFjY46KXHUwMDE0N8FHjveUxJrS3MXGXHUwMDFlyznAqdpmMciadkBh/KHXfan0dj41xt1cdTAwMTnisD1tNHufXHUwMDAy7E6ih1L0kpxcdTAwMWPORFx1MDAxNVZhq6NcdTAwMTDeXHUwMDBiXlx1MDAwNDDgXHUwMDA0IFxc5HxDgLfSi6FiXHUwMDE3UnpAMay7qt2LXHUwMDE1v64xXHUwMDFiKMup0WOQf5hd3t+a901Y3vnOUcxggftccotcXKc1O/pI8lx1MDAxNpI5Rlx1MDAwNFx0rOWQTcxcdLBccmSm3FjONED35nhcdTAwMDczV5/aXHUwMDFkrWt/XHLOUPiZd/Wvp1edSWlm+FqiJl4uXHUwMDBleIFcdTAwMDWKMCig5tfi1JiRgcH/39A8lsV7PJqC3tBzZ/3eotG2NK970V9UXHUwMDFm6/dS8Yhwylx1MDAwMC5cbmfvyFBcdGVcdTAwMTlcdTAwMTDB+fN45qAhXHUwMDFh1sx84/7puv3LnjA/10vFsznflEVcdTAwMWPRXCKLXHUwMDEw4oL43y9p1SNWP1x1MDAxMVlcZlx1MDAxMEpcdTAwMGJF1naqIFx1MDAxMqpcdTAwMGbnv1x1MDAxMfDJ6d4w0oOoMrMjK075685L1cL3yOxdynpfmPVcdTAwMDdXXHUwMDFmoiGhLVxcPoopclFMklx0QK2MSVxcmFx1MDAwMiX8mPorIys5XHUwMDA3yqwsVsRgq1wi1rhiWlx1MDAxOZXPoojRtLlcYupcdTAwMDPR6UxcdTAwMWbshkXDTmNo5rHRg8CfbVxiS8hrXGZoyodmXGKuhc6WOVx1MDAxNFFjyvVTUlx1MDAxZSjjTbB8gFx1MDAxM9Wwsi5cdTAwMTDEXFxoQFx1MDAxOcyY5MlCqlx1MDAxMeFcdTAwMDRRqDFBIKb8yFnKWfIuXHUwMDA1nos6zeqnMMWMtK2cKV2nYYZcdTAwMGbhdo99O3tcdTAwMWIq/qT/VdItS1x1MDAxZVb///26sPV2TpLaXHUwMDFjIen35Vx1MDAxNJCjh9GJ77p2pF7qMp7k5sxcdTAwMTNx/972TNtcdTAwMWJu1knP3FKT9KrHZ8SSulnQL1v3eJhcblx1MDAwZuWW85bZv7xOTLVcdTAwMWZcdTAwMDXKYdVomcTv8vT32ouzm8nJYorE6LSNwVxitvz+yzlcYsXXfpRcdTAwMTCtXHUwMDAxSrhcIlx1MDAxNaq/mUtcdTAwMTPLXHUwMDE4XHUwMDFlrFHOkFDOO6RcXMvcRzj0jaDfXHUwMDE0YE9qXHUwMDAxUFx1MDAxNpstmZTyvlx1MDAwMqDottBvkl3yxPxcIvsvVVDsUJTdeed6tFBA4v74/OpcXGveydGslFMhNp1VXG5woVOBRFx1MDAwMT/HUN3PXHIrJfnii1x1MDAwNblcdTAwMWIxscWaiz2vxCVhVNkmnFx1MDAxZTDMXFw3zcpLz/stTlx1MDAwNqY/XHUwMDFlP7Q/3p663HjjXHUwMDBm0G1U2lEgJJe8Zlx1MDAxMFx1MDAxNuJcZoqCL8eQXVx1MDAxOaJcdFx1MDAxMFRgVpg42ZHBXHUwMDE2UHlcdTAwMTecPk9UpXFyo79pXd54l/2JRlxmy/t48eG+XFy+WNu8JchcdTAwMTCtiWOm7WC8UI0pq0jk71x1MDAwNMZrulx1MDAxNVx1MDAxN6VcIpWfoFx1MDAxNObhXHUwMDA04IHybIZcdTAwMWFFXHUwMDA2OySfa5tmVjRcdTAwMTVcYr9Xj3ZCVVx1MDAxZo+vIz2K65ZIV6e2nL3Pk/HHIPnElvmPVz/+XHUwMDAxs5+03iJ9<!-- payload-end -->
+ <defs>
+ <style>
+ @font-face {
+ font-family: "Virgil";
+ src: url("https://excalidraw.com/Virgil.woff2");
+ }
+ @font-face {
+ font-family: "Cascadia";
+ src: url("https://excalidraw.com/Cascadia.woff2");
+ }
+ </style>
+ </defs>
+ <rect x="0" y="0" width="649.25" height="613" fill="#ffffff"></rect><g stroke-linecap="round" transform="translate(10 65.5) rotate(0 313.75 268.75)"><path d="M-0.64 0.27 C183.16 -1.41, 366.24 -0.99, 627.16 0.51 M-0.15 -0.1 C236.49 0.74, 472.1 0.89, 627.58 0.04 M627.21 -0.72 C626.48 193.78, 626.92 387.94, 628.16 537.25 M627.6 0.23 C626.3 157.65, 626.19 315.27, 627.48 537.61 M628.24 537.4 C433.34 538.98, 237.43 537.81, -0.4 537.85 M627.22 537.62 C394.58 539.45, 161.17 539.58, 0.16 537.15 M-0.55 537.11 C1.14 370.78, 1.74 202.32, -0.78 -0.26 M0.14 537.27 C0.47 350.59, 0.24 163.71, -0.21 0.08" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(10.5 10) rotate(0 314.375 27.5)"><path d="M-0.69 -0.79 C127.48 -0.76, 255.38 -0.98, 629.49 0.7 M-0.2 -0.18 C126.63 0.32, 253.87 0.26, 628.57 0.36 M630.22 1.63 C628.12 11.75, 630.32 26.32, 628.28 53.54 M628.96 -0.46 C630.15 16.06, 629.64 31.3, 628.68 55.27 M627.95 55.16 C438.86 56.91, 249.65 56.3, -0.66 55.38 M628.6 55.01 C476.39 54.97, 323.43 54.72, 0.08 55.29 M-1.67 56.06 C-0.22 42.88, 0.37 29.96, -0.66 0.81 M-0.87 54.22 C-0.63 33.16, -0.58 12.55, -0.53 -0.4" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(85 169.25) rotate(0 141.25 26.25)"><path d="M1.21 0.41 C68.36 -0.08, 136.37 0.62, 283.47 1.06 M0.21 0.65 C93.87 0.11, 186.6 0.74, 282.54 0.55 M282.46 -1.04 C282.42 15.3, 281.47 35.08, 281.87 53.39 M281.66 -0.58 C283.36 18.87, 281.88 39.9, 282.65 52.09 M282.87 52.04 C184.95 49.55, 87.55 50.33, 0.38 52.12 M282.75 52.39 C209.93 50.11, 138.48 50.34, -0.32 52.46 M1.68 51.38 C1.52 39.89, 0.18 28.67, 1.43 -1.8 M-0.79 51.78 C-0.51 40.69, -0.69 30.09, 0.57 0.22" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(88.75 137) rotate(0 38 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">currency</text></g><g stroke-linecap="round" transform="translate(85 303) rotate(0 151.24999999999994 22.5)"><path d="M0.91 -1.14 C95.79 -1.44, 190.83 -2.21, 302.59 -0.46 M-0.67 -0.65 C98.46 0.86, 196.25 0.51, 303.17 -0.24 M303.21 -0.52 C304.15 10.5, 304.18 22.15, 302.86 44.2 M302.76 -0.89 C301.3 15.99, 301.72 33.25, 301.94 45.83 M303.14 44.41 C194.91 45.12, 86.09 43.91, -0.44 44.54 M303.16 44.91 C192.69 46.89, 83.74 46.68, -0.07 45.58 M1.14 45.24 C0.92 29.4, 1.3 13.59, -0.8 -0.83 M0.16 45.29 C0.93 32.24, 0.27 21.07, -0.38 -0.09" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(311.25 171.75) rotate(0 28.75 25)"><path d="M0.44 -0.77 C14.94 -1.14, 28.74 1, 57.05 -0.33 M0.08 0.59 C16.41 -0.48, 30.76 0.45, 58.18 0.53 M58.91 0.53 C59.04 14.79, 59.13 29.43, 59.12 50.44 M57.26 -0.91 C57.45 13.3, 58.12 25.66, 57.66 50.88 M58.73 49.01 C41.72 51.08, 27.73 49.64, 1.53 49.91 M57.62 49.75 C34.13 49.25, 11.8 50.29, 0.88 49.68 M0.38 51.81 C2.16 34.87, 0.54 24.89, 0.68 0.55 M0.44 49.31 C-1.01 30.58, 0.05 10.84, 0.61 0.3" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(86.25 267) rotate(0 43 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">exchange</text></g><g transform="translate(97.5 314.5) rotate(0 63 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">demo.taler.net</text></g><g transform="translate(113 185.75) rotate(0 21.5 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">EUR</text></g><g transform="translate(77.5 392) rotate(0 33 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">amount</text></g><g stroke-linecap="round" transform="translate(77.5 423) rotate(0 157.5 25.625)"><path d="M0.98 -1.01 C93.63 -1.56, 187.05 -3.04, 315.73 1.11 M-0.04 -0.04 C73.77 -1.1, 147.37 -0.72, 314.99 0.25 M315.02 0.27 C313.45 15.41, 314.14 29.54, 316.03 53 M315.56 -0.56 C314.38 19.16, 315.73 36.89, 315.62 50.8 M315.01 51.64 C198.27 52.87, 77.9 51.61, -0.42 51.5 M315.63 51.68 C235.57 50.27, 157.37 48.94, -0.59 51.29 M-1.47 51.7 C-2.4 38.22, -1.94 25.61, -0.44 -1.56 M0.68 50.43 C-1.32 35.36, 0.49 21.68, -0.96 -0.5" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(372.5 520.5) rotate(0 115 26.25)"><path d="M0.51 -0.64 C92.55 2.54, 183 2.13, 229.93 -0.07 M0.15 0.19 C65.69 1.02, 132.13 2.16, 229.76 -0.72 M229.11 1.89 C230.91 18.79, 228.5 38.07, 229.53 53.38 M230.66 0.83 C230.81 16.54, 229.79 34.44, 230.53 52.73 M229 53.36 C174.76 53.18, 121.58 52.1, 1.39 53.28 M230.71 52.74 C155.74 52.99, 81.01 53.08, -0.33 51.67 M0.52 53.55 C-1.36 39.47, -0.09 24.78, 0.87 1.84 M-0.64 51.9 C-0.32 36.64, 0.36 20.89, 0.12 -0.53" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g transform="translate(407.5 538.75) rotate(0 69.5 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#364fc7" text-anchor="start" style="white-space: pre;" direction="ltr">start withdrawal</text></g><g stroke-linecap="round" transform="translate(321.25 299) rotate(0 31.875 23.75)"><path d="M0.91 0.47 C20.99 -1.15, 47.29 1.06, 63.61 1.5 M-0.45 -0.41 C19.5 -0.46, 40.52 -0.3, 64.3 0.46 M65.47 1.81 C63.31 12.54, 65.46 28.51, 63.36 46.29 M63.61 0.61 C62.98 11.81, 62.86 25.37, 63.81 48.33 M62.66 48.86 C43.77 48.27, 24.95 48.59, -0.58 46.58 M64.61 47.11 C49.77 47.35, 34.75 47.13, 0.07 47.88 M-0.29 48.17 C-2.19 29.17, -0.3 11.96, -0.98 1.71 M0.7 47.1 C0.04 33.01, -1.35 17.47, -0.73 -0.83" stroke="#000000" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(352.60947862109833 311.65257480315864) rotate(0 1.4633860506549468 11.261301259659206)"><path d="M-0.49 -0.03 C-0.24 3.78, 0.68 18.59, 1.29 22.17 M1.45 -1.1 C2.08 2.97, 3.2 19.72, 3.42 23.62" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(352.60947862109833 311.65257480315864) rotate(0 1.4633860506549468 11.261301259659206)"><path d="M-1.12 12.29 C-0.05 16.92, 0.53 18.56, 2.44 24.48 M-0.95 13.8 C0.07 16.86, 1.42 19.69, 3.08 23.78" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(352.60947862109833 311.65257480315864) rotate(0 1.4633860506549468 11.261301259659206)"><path d="M6.55 11.8 C5.47 16.54, 3.89 18.32, 2.44 24.48 M6.73 13.31 C5.4 16.51, 4.4 19.5, 3.08 23.78" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g stroke-linecap="round"><g transform="translate(337.05473931054917 184.57628740157924) rotate(0 1.5295271914883983 11.188407159857434)"><path d="M0.43 -0.55 C0.52 3.3, 1.07 19.06, 1.58 22.93 M-0.8 1.78 C-0.42 5.28, 3.19 17.38, 3.86 21.11" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(337.05473931054917 184.57628740157924) rotate(0 1.5295271914883983 11.188407159857434)"><path d="M-2.85 10.97 C0.59 16.31, 2.72 18.44, 3.1 22.21 M-2.68 11.97 C0.41 15.44, 2.12 18.93, 3.78 21.23" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(337.05473931054917 184.57628740157924) rotate(0 1.5295271914883983 11.188407159857434)"><path d="M4.63 9.18 C5.18 15.24, 4.43 18.06, 3.1 22.21 M4.8 10.19 C5.06 14.27, 3.92 18.44, 3.78 21.23" stroke="#000000" stroke-width="1" fill="none"></path></g></g><g transform="translate(422.5 316.75) rotate(0 64 11.5)"><text x="0" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="start" style="white-space: pre;" direction="ltr">Add exchange</text></g><g stroke-linecap="round" transform="translate(76.25 424.75) rotate(0 50 25.625)"><path d="M0.77 1.74 C24.32 0.96, 44.2 -1.69, 98.65 1.57 M-0.69 0.75 C21.48 -0.76, 43.4 0.32, 100.75 -0.92 M100.71 -0.97 C99.78 15.92, 101.32 30.35, 99.88 50.27 M100.65 0.76 C99.43 14.4, 101.11 27.48, 100.96 50.81 M98.17 49.87 C65.22 52.06, 33 50.69, 1.35 50.22 M99.74 51.11 C68.13 52.11, 37.2 52.49, -0.3 50.26 M-1.09 53.01 C1.03 36.68, -0.88 21.05, -0.53 0.24 M0.79 50.4 C0.83 34.32, -0.05 16.09, 0.79 0.09" stroke="#000000" stroke-width="1" fill="none"></path></g><g transform="translate(104.75 438.875) rotate(0 21.5 11.5)"><text x="21.5" y="17" font-family="Helvetica, Segoe UI Emoji" font-size="20px" fill="#000000" text-anchor="middle" style="white-space: pre;" direction="ltr">EUR</text></g></svg> \ No newline at end of file
diff --git a/index.rst b/index.rst
index c16a9125..bd3b30d6 100644
--- a/index.rst
+++ b/index.rst
@@ -1,6 +1,6 @@
..
This file is part of GNU TALER.
- Copyright (C) 2014-2021 Taler Systems SA
+ Copyright (C) 2014-2023 Taler Systems SA
TALER 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
@@ -37,39 +37,33 @@ practice a fraudulent Exchange might go bankrupt instead of paying the
Merchants and thus the Exchange will need to be audited regularly like
any other banking institution.
-The system will be based on free software and open protocols.
+The system is based on free software and open protocols.
+
+In this documentation, we describe the REST-based APIs between the various
+components, how to use the system, the internal architecture of key
+components, and how to get them installed and configured.
-In this document, we describe the REST-based APIs between the various
-components, internal architecture of key components, and how to get them
-installed. In addition to this documentation, we have source-level
-documentation which you can find converted to HTML at these pages:
-* `Exchange <https://docs.taler.net/doxygen/exchange/>`_
-* `Merchant <https://docs.taler.net/doxygen/merchant/>`_
-* `Wallet-core <https://docs.taler.net/doxygen/wallet-core/>`_
Documentation Overview
----------------------
.. toctree::
:numbered:
- :maxdepth: 2
+ :maxdepth: 1
core/index
- taler-exchange-manual
- taler-exchange-setup-guide
+ taler-user-guide
taler-merchant-manual
- taler-wallet-cli-manual
- taler-nfc-guide.rst
taler-merchant-api-tutorial
taler-merchant-pos-terminal
- taler-bank-manual
- taler-backoffice-manual
+ taler-wallet
+ taler-exchange-manual
+ taler-challenger-manual
taler-auditor-manual
taler-developer-manual
- taler-wallet
- design-documents/index
libeufin/index
+ design-documents/index
global-licensing
manindex
genindex
diff --git a/libeufin/api-nexus.rst b/libeufin/api-nexus.rst
deleted file mode 100644
index 5f3e7a6c..00000000
--- a/libeufin/api-nexus.rst
+++ /dev/null
@@ -1,1044 +0,0 @@
-.. target audience: core developer
-
-Nexus API
-###########
-
-.. contents:: Table of Contents
-
-HTTP API
-========
-
-Configuration
--------------
-
-Returns configuration values currently used by the Nexus process.
-This API is mostly used by testing jobs.
-
-.. http:get:: {nexusBase}/service-config
-
- **Response:**
-
- .. ts:def:: ServiceConfigResponse
-
- interface ConfigResponse {
-
- // Connection string to the database.
- dbConn: string;
- }
-
-
-Returns configuration values currently used by Nexus.
-
-.. http:get:: {nexusBase}/config
-
- **Response:**
-
- .. ts:def:: ConfigResponse
-
- interface ConfigResponse {
-
- currency: string;
-
- // nexus version, X.Y.Z format.
- version: string;
- }
-
-
-Authentication
---------------
-
-Currently every request made to nexus must be authenticated using the *HTTP
-basic auth* mechanism.
-
-Other authentication mechanisms (e.g. OpenID Connect) might
-be supported in the future.
-
-User Management
----------------
-
-.. http:get:: {nexusBase}/user
-
- Get information about the current user (based on the authentication information
- in this request).
-
- **Response:**
-
- .. ts:def:: GetUserResponse
-
- interface UserResponse {
-
- // User name
- username: string;
-
- // Password
- password: string;
- }
-
-.. http:post:: {nexusBase}/users/password
-
- Change password of a user. The username is extracted from
- the HTTP authentication parameters.
-
- **Request:**
-
- .. code-block:: ts
-
- interface UserChangePassword {
- newPassword: string;
- }
-
-.. http:post:: {nexusBase}/users
-
- Create a new user. Only a superuser can call this API.
-
- **Request:**
-
- The body is a `User` object.
-
- **Response:**
-
- :http:statuscode:`409 Conflict`: Username is not available.
-
- **Details:**
-
- .. ts:def:: User
-
- interface User {
-
- // User name
- username: string;
-
- // Initial password
- password: string;
- }
-
-
-.. http:get:: {nexusBase}/users
-
- Return list of users.
-
-.. _nexus-permissions-api:
-
-Permissions API
----------------
-
-The permissions API manages authorization of access of subjects (usually users)
-to resources.
-
-Permissions are modeled a set of ``(subject, resource, permission)`` triples.
-Subjects and resources consist of a type and an identifier.
-
-Superusers are not subject to further permission checks, they are allowed
-to do any operation.
-
-The following subject types are currently supported:
-
-* ``user``: An authenticated user. The subject ID
- is interpreted as the user ID.
-
-The following permissions are currently defined:
-
-* ``facade.talerWireGateway.history``: Allows querying the
- transaction history through a Taler wire gateway facade.
-* ``facade.talerWireGateway.transfer``: Allows creating payment initiations
- to transfer money via a Taler wire gateway facade.
-
-The following resource IDs are currently supported:
-
-* ``facade``: A LibEuFin facade. The resource ID is interpreted as the
- facade name.
-
-.. http:get:: {nexusbase}/permissions
-
- List all permissions.
-
- **Response**
-
- .. ts:def:: QueryPermissionsResponse
-
- interface QueryPermissionsResponse {
- permissions: {
- subjectType: string;
- subjectId: string;
- resourceType: string;
- resourceId: string;
- permissionName: string
- }[];
- }
-
-.. http:post:: {nexusbase}/permissions
-
- Modify permissions.
-
- **Request**
-
- .. ts:def:: QueryPermissionsResponse
-
- interface QueryPermissionsResponse {
- action: "grant" | "revoke";
- permission: {
- subjectType: string;
- subjectId: string;
- resourceType: string;
- resourceId: string;
- permissionName: string
- };
- }
-
- **Response**
-
- The response is an empty JSON object.
-
-
-Test API
---------
-
-
-.. http:post:: {nexusbase}/bank-accounts/{acctid}/test-camt-ingestion/{type}
-
- This call allows tests to **directly** give Nexus a Camt document. After
- the processing, all the payment(s) details should be ingested as if the
- Camt came normally from a bank / the Sandbox. ``acctid`` must match the
- label of a locally imported bank account, and ``type`` for now can only be
- ``C53``.
-
- **Response**
-
- The successful case should respond with a ``200 OK`` and a empty JSON body.
-
-
-Bank Accounts
--------------
-
-The LibEuFin maintains a copy of the bank account transaction history and balance information,
-manages payment initiations of the account and tracks the initiations of payments.
-
-.. http:get:: {nexusBase}/bank-accounts
-
- **Response:**
-
- A list of `BankAccount` objects
- that belong to the requester.
-
- .. ts:def:: BankAccount
-
- interface BankAccount {
- // mnemonic name identifying this bank account.
- nexusBankAccountId: string;
- // IBAN
- iban: string;
- // BIC
- bic: string;
- // Legal subject owning the account.
- ownerName: string;
- }
-
-
-.. http:get:: {nexusBase}/bank-accounts/{my-acct}
-
- Get basic information about the bank account named ``my-acct``.
-
- interface BankAccountInfoWithBalance {
- // ID number of the database row being the default bank connection
- // of `my-acct`.
- defaultBankConnection: number;
- // Payto://-URI of `my-acct`.
- accountPaytoUri: string;
- // Balance of `my-acct` as it was downloaded from the bank
- // along the last Camt document. A human-readable message
- // will inform the requester, should this value not be found.
- lastSeenBalance: string;
- }
-
-.. http:post:: {nexusBase}/bank-accounts/{acctid}/payment-initiations/{pmtid}/submit
-
- Ask nexus to submit one prepare payment at the bank.
-
- :http:statuscode:`404 Not found`: the unique identifier **or**
- the bank connection could not be found in the system
-
-
-.. http:get:: {nexus}/bank-accounts/{my-acct}/payment-initiations/{uuid}
-
- Ask the status of payment ``$uuid``.
-
- **Response:**
-
- .. ts:def:: PaymentStatus
-
- interface PaymentStatus {
- // Can be "BOOK" or "PDNG" ('pending').
- status: string;
-
- // Payment unique identifier
- paymentInitiationId: string;
-
- // True for submitted payments
- submitted: boolean;
-
- // Creditor IBAN
- creditorIban: string;
-
- // Creditor BIC
- creditorBic: string;
-
- // Creditor legal name
- creditorName: string;
-
- // Amount
- amount: string;
-
- // Subject
- subject: string;
-
- // Date of submission (in dashed form YYYY-MM-DD)
- submissionDate: string;
-
- // Date of preparation (in dashed form YYYY-MM-DD)
- preparationDate: string;
- }
-
-.. http:get:: {nexusBase}/bank-accounts/{my-acct}/payment-initiations
-
- Ask nexus the list of initiated payments. At this stage of the API,
- **all** is returned: submitted and non-submitted payments.
-
- **Response**
-
- .. ts:def:: InitiatedPayments
-
- interface InitiatedPayments {
-
- // list of all the initiated payments' UID.
- initiatedPayments: PaymentStatus[];
- }
-
-
-.. http:post:: {nexusBase}/bank-accounts/{my-acct}/payment-initiations
-
- Ask nexus to prepare instructions for a new payment.
- Note that ``my-acct`` is the bank account that will be
- **debited** after this operation.
-
- **Request:**
-
- .. ts:def:: PreparedPaymentRequest
-
- interface PreparedPaymentRequest {
- // IBAN that will receive the payment.
- iban: string;
- // BIC hosting the IBAN.
- bic: string;
- // Legal subject that will receive the payment.
- name: string;
- // payment subject.
- subject: string;
- // amount, in the format CURRENCY:XX.YY
- amount: string
- }
-
- **Response:**
-
- .. ts:def:: PreparedPaymentResponse
-
- interface PreparedPaymentResponse {
-
- // Opaque identifier to be communicated when
- // the user wants to submit the payment to the
- // bank.
- uuid: string;
- }
-
-.. http:post:: {nexusBase}/bank-accounts/{acctid}/fetch-transactions
-
- Nexus will download bank transactions using the given connection.
-
- **Request:**
-
- .. ts:def:: CollectedTransaction
-
- interface CollectedTransaction {
-
- // This type indicates the time range of the query.
- // It can assume the following values:
- //
- // 'latest': retrieves the last transactions from the bank.
- // If there are older unread transactions, those will *not*
- // be downloaded.
- //
- // 'all': retrieves all the transactions from the bank,
- // until the oldest.
- //
- // 'previous-days': currently *not* implemented, it will allow
- // the request to download transactions from
- // today until N days before.
- //
- // 'since-last': retrieves all the transactions since the last
- // time one was downloaded.
- //
- rangeType: string;
-
- // Because transactions are delivered by banks in "batches",
- // then every batch can have different qualities. This value
- // lets the request specify which type of batch ought to be
- // returned. Currently, the following two type are supported:
- //
- // 'report': intra-day information
- // 'statement': prior day bank statement
- level: string;
-
- // Bank connection to use. It is a *optional* value that
- // defaults to the default bank connection, if not given.
- bankConnection: string;
- }
-
- **Response:**
-
- .. code-block:: ts
-
- interface NewTransactions {
- // How many transactions are new to Nexus.
- newTransactions: number;
- // How many transactions got downloaded by the request.
- // Note that a transaction can be downloaded multiple
- // times but only counts as new once.
- downloadedTransactions: number;
- }
-
-.. http:get:: {nexusBase}/bank-accounts/{acctid}/transactions
-
- Shows which transactions are stored locally at nexus.
-
- **Query parameters:**
-
- * **start** start (dashed YYYY-MM-DD) date of desired payments.
- Optional, defaults to "earliest possible" date.
- * **end** end (dashed YYYY-MM-DD) date of desired payments.
- Optional, defaults to "earliest possible" date.
-
-
- **Response:** A object with a unique field named ``transactions``
- that contains a list of `Transaction` objects.
-
- .. ts:def:: Transaction
-
- interface Transaction {
-
- // money moved by the transaction
- amount: string;
-
- // CRDT or DBIT
- creditDebitIndicator: string
-
- // Two of the most used values are BOOK, or PENDING
- status: string;
-
- // FIXME
- bankTransactionCode: string;
-
- // FIXME
- valueDate: string;
-
- // When this payment got booked. In the form YYYY-MM-DD
- bookingDate: string;
-
- // FIXME
- accountServicerRef: string;
-
- // FIXME
- batches: {
- // list of batched transactions
- batchTransactions: BatchedTransaction[];
- };
- }
-
- .. ts:def:: BatchedTransaction
-
- interface BatchedTransaction {
- // FIXME
- amount: string;
- // FIXME
- creditDebitIndicator: string;
- // FIXME
- details {
- debtor: {
- name: string;
- };
- debtorAccount: {
- iban: string;
- };
- // Missing, when the payment is DBIT.
- debtorAgent: {
- bic: string;
- };
- creditor: {
- name: string;
- };
- creditorAccount: {
- iban: string;
- };
- // Missing, when the payment is CRDT.
- creditorAgent: {
- iban: string;
- };
- // FIXME
- endToEndId: string;
- // FIXME
- unstructuredRemittanceInformation: string;
- }
- }
-
-Scheduling API
---------------
-
-.. http:post:: {nexusBase}/bank-accounts/{acctid}/schedule
-
- This endpoint allows the caller to define a recurrent
- execution of a task.
-
- **Request**
-
- .. ts:def:: ScheduleTask
-
- interface ScheduleTask {
- name: string;
-
- // a Unix-compatible cron pattern representing
- // the frequency of execution of this task.
- cronspec: string;
-
- // Can take values "fetch" (to download the history
- // of the requester's bank account) or "submit" (to submit
- // any initiated payment associated to the requester's
- // bank account).
- type: string;
-
- // Currently only used for "fetch" operations
- params: {
- level: "report" | "statement" | "all";
- rangeType: "latest" | "all" | "previous-days" | "since-last";
- };
- }
-
-
-
-.. http:get:: {nexusBase}/bank-accounts/{acctid}/schedule/{taskId}
-
- **Response**
-
- .. ts:def:: NexusTask
-
- // This object is a mere reflection of
- // what the Nexus database keeps to implement
- // the scheduling feature.
-
- interface NexusTask {
- // FIXME: document all.
- resourceType: string;
- resourceId: string;
- taskName: string;
- taskType: string;
- taskCronSpec: string;
- taskParams: string;
- nextScheduledExecutionSec: number;
- prevScheduledExecutionSec: number;
- }
-
-
-.. http:delete:: {nexusBase}/bank-accounts/{acctid}/schedule/{taskId}
-
- This call deletes the task associated to ``taskId``.
-
-.. http:get:: {nexusBase}/bank-accounts/{acctid}/schedule
-
- **Response**
-
- .. code-block:: ts
-
- interface TaskCollection {
-
- // This field can contain *multiple* objects of the type sampled below.
- schedule: {
-
- 'task-name': {
- cronspec: string;
- type: string; // fetch | submit
-
- // Depends on the type. Submit has it empty, whereas
- // the fetch type includes the time range and the report
- // level.
- params: any;
- }
- }
- }
-
-
-Bank Connections
-----------------
-
-Bank connections connect the local LibEuFin bank account
-to the real bank.
-
-.. http:post:: <nexus>/bank-connections
-
- Activate a new bank connection for the requesting user.
-
- **Request:**
-
- This request can accept two formats, depending on whether a
- new bank connection is being made, or a connection backup is
- being restored.
-
-
- This type allows the creation of new bank accounts.
-
- .. ts:def:: NewBankConnection
-
- interface NewBankConnection {
-
- source: string; // only "new" allowed
-
- // connection name.
- name: string;
-
- // type of the connection to make: "ebics" for example.
- type: string;
-
- data: BankConnectionNew;
- }
-
- This type allows to restore a previously made bank connection.
-
- .. ts:def:: BankConnectionRestoreRequest
-
- interface BankConnectionRestoreRequest {
-
- source: "backup";
-
- // connection name.
- name: string;
-
- // Backup data, as typically returned by the "../export-backup" API.
- backup: BankConnectionBackup;
-
- passphrase?: string;
- }
-
-
- .. ts:def:: BankConnectionNew
-
- interface BankConnectionNew {
-
- // This type is strictly dependent on
- // the connection being created. For Ebics,
- // it will contain the required fields (as strings):
- // 'ebicsURL', 'userID', 'partnerID', 'hostID', and
- // the optional 'systemID'.
-
- // Other connection types, like 'local' (used for testing
- // purposes skipping any interaction with the bank service)
- // and 'fints' are all work in progress!
-
- }
-
-
- .. ts:def:: BankConnectionBackup
-
- interface BankConnectionBackup {
-
- // The information needed in this type depend entirely
- // on which connection is being restored.
- }
-
- **Response:**
-
- :http:statuscode:`406 Not acceptable`: a connection with the
- requested name already exists for this user.
-
-.. http:post:: {nexusBase}/bank-connections/delete-connection
-
- **Request:**
-
- .. ts:def:: BankConnectionDeletion
-
- interface BankConnectionDeletion {
- // label of the bank connection to delete
- bankConnectionId: string;
- }
-
-.. http:get:: {nexusBase}/bank-connections
-
- List available bank connections.
-
- **Response**
-
- A JSON object whose ``bankConnections`` element is a list of the following type:
-
- .. ts:def:: BankConnection
-
- interface BankConnection {
-
- // connection type. For example "ebics".
- type: string;
-
- // connection name as given by the user at
- // the moment of creation.
- name: string;
- }
-
-
-.. http:get:: {nexusBase}/bank-connections/{connId}
-
- Get information about one bank connection.
-
- .. ts:def:: BankConnectionInfo
-
- interface BankConnectionInfo {
- type: string;
- owner: string;
- // if true, this connection can be used to communicate
- // with the bank.
- ready: boolean;
- // Depends on the type.
- details: any;
- }
-
-
-.. http:post:: {nexusBase}/bank-connections/{connId}/connect
-
- Initialize the connection by talking to the bank.
-
-.. http:post:: {nexusBase}/bank-connections/{connId}/export-backup
-
- Make a passphrase-encrypted backup of this connection.
-
-.. http:post:: {nexusBase}/bank-connections/{connId}/fetch-accounts
-
- Update accounts that are accessible via this bank connection.
-
-.. http:get:: {nexusBase}/bank-connections/{connId}/accounts
-
- List the bank accounts that this bank connection provides access to.
-
- .. ts:def:: OfferedBankAccount
-
- interface OfferedBankAccount {
-
- // Unique identifier for the offered account
- offeredAccountId: string;
-
- // IBAN of the offered account
- iban: string;
-
- // BIC of the account's financial institution
- bic: string;
-
- // Account owner name
- ownerName: string;
-
- // If the account has been imported,
- // this field contains the ID of the
- // Nexus bank account associated with it.
- nexusBankAccountId: string | null;
- }
-
-.. http:post:: {nexusBase}/bank-connections/{connId}/import-account
-
- Import a bank account provided by the connection into the Nexus.
-
- If no Nexus bank account with the ID ``nexusBankAccountId`` exists,
- a new one will be created, and it will have ``connId`` as the
- default bank connection.
-
- If an existing Nexus bank account with the same ID already exists,
- this connection will be added as an available connection for it.
- This only succeeds if the bank account has the same IBAN.
-
- .. ts:def:: ImportBankAccount
-
- interface ImportBankAccount {
-
- // Identifier for the bank account, as returned by /accounts
- // of the bank connection.
- offeredAccountId: string;
-
- // Nexus-local identifier for the bank account.
- nexusBankAccountId: string;
- }
-
-
-.. http:get:: <nexus>/bank-connections/{connId}/messages
-
- List *some* details of all the ISO2022 messages gotten from the bank. It
- responds with a list of the following elements:
-
- .. code-block:: ts
-
- interface BankMessageInfo {
-
- // the message type, typically how the containing layer
- // (Ebics, for example) would label this information. For
- // Camt.053 types, this value is "C53".
- code: string;
-
- // the unique identifier of the message.
- messageId: string;
-
- // bytes length of the message.
- length: number;
- }
-
-
-
-.. http:get:: <nexus>/bank-connections/{connId}/messages/{msgId}
-
- Return the ISO20022 XML corresponding to ``msgId``.
-
-
-Facades
--------
-
-.. http:get:: <nexus>/facades/{fcid}
-
- **Response:** A `FacadeShowInfo` pointed to by ``fcid``.
-
-
-.. http:get:: <nexus>/facades
-
- List available facades that belong to the requesting user.
-
- **Response:** A list of the following elements:
-
-.. ts:def:: FacadeShowInfo
-
- interface FacadeShowInfo {
-
- // Name of the facade, same as the "fcid" parameter.
- name: string;
-
- // Type of the facade.
- // For example, "taler-wire-gateway".
- type: string;
-
- // Bas URL of the facade.
- baseUrl: string;
-
- // details depending on the facade type.
- config: any;
- }
-
-.. http:delete:: {nexus}/facades/{fcid}
-
- Delete a facade.
-
-.. http:post:: {nexus}/facades
-
- Create a new facade.
-
- **Request:**
-
- .. code-block:: ts
-
- interface FacadeInfo {
- // Name of the facade, same as the "fcid" parameter.
- name: string;
-
- // Type of the facade.
- // For example, "taler-wire-gateway" or "anastasis".
- type: string;
-
- // Bank accounts that the facade has read/write
- // access to.
- bankAccountsRead: string[];
- bankAccountsWrite: string[];
-
- // Bank connections that the facade has read/write
- // access to.
- bankConnectionsRead: string[];
- bankConnectionsWrite: string[];
-
- // Facade-specific configuration details.
- config: any;
- }
-
-
-Bank Connection Protocols
--------------------------
-
-.. http:get:: {nexus}/bank-connection-protocols
-
- List supported bank connection protocols.
-
-.. http:post:: {nexus}/bank-connection-protocols/ebics/test-host
-
- Check if the nexus can talk to an EBICS host.
- This doesn't create a new connection in the database,
- and is useful during setup when the user hasn't entered
- the full details for the connection yet.
-
- .. ts:def:: EbicsHostTestRequest
-
- interface EbicsHostTestRequest {
- ebicsBaseUrl: string;
- ebicsHostId: string;
- }
-
-
-EBICS-specific APIs
--------------------
-
-The following endpoints are only available for EBICS bank connections.
-They are namespaced under the ``/ebics/`` sub-resource.
-
-.. http:post:: {nexusBase}/bank-connections/{connection-name}/ebics/download/{msg}
-
- .. warning::
-
- Use with care. Typically only necessary for testing and debugging.
-
- Perform an EBICS download transaction of type ``msg``.
- This request will not affect any bank account or other state
- in the nexus database. It will just make a request to the bank
- and return the answer.
-
-.. http:post:: {nexusBase}/bank-connections/{connection-name}/ebics/upload/{msg}
-
- .. warning::
-
- Use with care. Typically only necessary for testing and debugging.
-
- Perform an EBICS upload transaction of type ``msg``.
- This request will not affect any bank account or other state
- in the nexus database. It will just make a request to the bank
- and return the answer.
-
-Anastasis API.
---------------
-
-This is a read-only API offering a view over *only* the incoming
-transactions of a bank account. It is named after the typical user -
-a Anastasis service - but can be used in any case where only the
-incoming transactions are of interest.
-
-.. http:get:: ${BASE_URL}/history/incoming
-
- Return a list of transactions made to the customer.
-
- The bank account of the customer is determined via the base URL and/or the
- user name in the ``Authorization`` header. In fact the transaction history
- might come from a "virtual" account, where multiple real bank accounts are
- merged into one history.
-
- Transactions are identified by an opaque numeric identifier, referred to here
- as *row ID*. The semantics of the row ID (including its sorting order) are
- determined by the bank server and completely opaque to the client.
-
- The list of returned transactions is determined by a row ID *starting point*
- and a signed non-zero integer *delta*:
-
- * If *delta* is positive, return a list of up to *delta* transactions (all matching
- the filter criteria) strictly **after** the starting point. The transactions are sorted
- in **ascending** order of the row ID.
- * If *delta* is negative, return a list of up to *-delta* transactions (all matching
- the filter criteria) strictly **before** the starting point. The transactions are sorted
- in **descending** order of the row ID.
-
- If *starting point* is not explicitly given, it defaults to:
-
- * A value that is **smaller** than all other row IDs if *delta* is **positive**.
- * A value that is **larger** than all other row IDs if *delta* is **negative**.
-
- **Request**
-
- :query start: *Optional.*
- Row identifier to explicitly set the *starting point* of the query.
- :query delta:
- The *delta* value that determines the range of the query.
- :query long_poll_ms: *Optional.* If this parameter is specified and the
- result of the query would be empty, the bank will wait up to ``long_poll_ms``
- milliseconds for new transactions that match the query to arrive and only
- then send the HTTP response. A client must never rely on this behavior, as
- the bank may return a response immediately or after waiting only a fraction
- of ``long_poll_ms``.
-
- **Response**
-
- :http:statuscode:`200 OK`: JSON object of type `IncomingHistory`.
- :http:statuscode:`400 Bad request`: Request malformed. The bank replies with an `ErrorDetail` object.
- :http:statuscode:`401 Unauthorized`: Authentication failed, likely the credentials are wrong.
- :http:statuscode:`404 Not found`: The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object.
-
- .. ts:def:: IncomingHistory
-
- interface IncomingHistory {
-
- // Array of incoming transactions.
- incoming_transactions : IncomingBankTransaction[];
-
- }
-
- .. ts:def:: IncomingBankTransaction
-
- interface IncomingBankTransaction {
-
- // Opaque identifier of the returned record.
- row_id: SafeUint64;
-
- // Date of the transaction.
- date: Timestamp;
-
- // Amount transferred.
- amount: Amount;
-
- // Payto URI to identify the receiver of funds.
- // This must be one of the exchange's bank accounts.
- credit_account: string;
-
- // Payto URI to identify the sender of funds.
- debit_account: string;
-
- // subject of the incoming payment.
- subject: string;
-
- }
-
-The anastasis facade
---------------------
-
-The ``anastasis`` facade has the following configuration:
-
-
-.. ts:def:: AnastasisFacadeConfig
-
- interface AnastasisFacadeConfig {
- // Bank account and connection that is abstracted over.
- bankAccount: string;
- bankConnection: string;
-
- currency: string;
-
- // Corresponds to whether we trust C52, C53 or C54 (SEPA ICT)
- // for incoming transfers.
- reserveTransferLevel: "statement" | "report" | "notification";
- }
-
-The taler-wire-gateway facade
------------------------------
-
-The ``taler-wire-gateway`` facade has the following configuration:
-
-
-.. ts:def:: TalerWireGatewayFacadeConfig
-
- interface TalerWireGatewayFacadeConfig {
- // Bank account and connection that is
- // abstracted over.
- bankAccount: string;
- bankConnection: string;
-
- currency: string;
-
- // Corresponds to whether we trust C52, C53 or C54 (SEPA ICT)
- // for incoming transfers.
- reserveTransferLevel: "statement" | "report" | "notification";
- }
diff --git a/libeufin/api-sandbox.rst b/libeufin/api-sandbox.rst
deleted file mode 100644
index b30061ae..00000000
--- a/libeufin/api-sandbox.rst
+++ /dev/null
@@ -1,232 +0,0 @@
-.. target audience: developer, core developer
-
-.. _sandbox-api:
-
-Sandbox API
-###########
-
-..
- Current Sandbox endpoints.
-
- POST /register
- GET /jinja-test
- GET /profile
- GET /static
- GET /
- GET /config
- POST /admin/payments/camt
- POST /admin/bank-accounts/$accountLabel
- GET /admin/bank-accounts/$accountLabel
- POST /admin/bank-accounts/$accountLabel/simulate-incoming-transaction
- POST /admin/payments
- POST /admin/ebics/bank-accounts
- GET /admin/bank-accounts
- GET /admin/bank-accounts/$accountLabel/transactions
- POST /admin/bank-accounts/$accountLabel/generate-transactions
- POST /admin/ebics/subscribers
- GET /admin/ebics/subscribers
- POST /admin/ebics/hosts/$hostID/rotate-keys
- POST /admin/ebics/hosts
- GET /admin/ebics/hosts
- POST /ebicsweb
-
-HTTP API
-========
-
-..
- Payments.
-
-
-.. http:post:: /admin/payments/camt
-
- Return the history of one IBAN in Camt.053 format.
-
- **Request**
-
- .. code-block:: tsref
-
- interface CamtParams {
-
- // label of the bank account being queried.
- bankaccount: string;
-
- // The Camt type to return. Only '53' is allowed
- // at this moment.
- type: number;
- }
-
- **Response**
-
- The expected Camt.053 document.
-
-.. http:post:: /admin/payments
-
- Adds a new payment to the book. Mainly used for testing
- purposes.
-
- **Request:**
-
- One object of type `SandboxPayment`
-
- .. ts:def:: SandboxPayment
-
- interface SandboxPayment {
-
- // IBAN that will receive the payment.
- creditorIban: string;
- // FIXME
- creditorBic: string;
- // FIXME
- creditorName: string;
-
- // IBAN that will send the payment.
- debitorIban: string;
- // FIXME
- debitorBic: string;
- // FIXME
- debitorName: string;
-
- amount: string;
- currency: string;
-
- // subject of the payment.
- subject: string;
-
- // Whether the payment is credit or debit *for* the
- // account being managed *by* the running sandbox.
- // Can take the values: "CRDT" or "DBIT".
- direction: string;
- }
-
-..
- Host management.
-
-.. http:post:: /admin/ebics/hosts
-
- Creates a new Ebics host.
-
- **Request:**
-
- .. ts:def:: EbicsHostRequest
-
- interface EbicsHostRequest {
-
- // Ebics version.
- hostID: string;
-
- // Name of the host.
- ebicsVersion: string;
- }
-
-
-.. http:get:: /admin/ebics/hosts
-
- Shows the list of all the hosts in the system.
-
- **Response:**
-
- .. ts:def:: EbicsHostResponse
-
- interface EbicsHostResponse {
-
- // shows the host IDs that are active in the system.
- // The Ebics version *is* missing, but it's still available
- // via the HEV message.
- ebicsHosts: string[];
- }
-
-.. http:post:: /admin/ebics/hosts/$hostID/rotate-keys
-
- Overwrite the bank's Ebics keys with random ones. This is entirely
- meant for tests (as the Sandbox itself is) and no backup will be
- produced along this operation.
-
-..
- Subscriber management.
-
-.. http:post:: /admin/ebics/subscribers
-
- Creates a new Ebics subscriber.
-
- **Request:**
-
- .. ts:def:: SubscriberRequest
-
- interface SubscriberRequest {
-
- // hostID
- hostID: string;
-
- // userID
- userID: string;
-
- // partnerID
- partnerID: string;
-
- // systemID
- systemID: string;
-
- }
-
-
-.. http:get:: /admin/ebics/subscribers
-
- Shows the list of all the subscribers in the system.
-
- **Response:**
-
- .. ts:def:: SubscribersResponse
-
- interface SubscribersResponse {
-
- subscribers: Subscriber[]
- }
-
- .. ts:def:: Subscriber
-
- interface Subscriber {
-
- // userID
- userID: string;
-
- // partnerID
- partnerID: string;
-
- // hostID
- hostID: string;
-
- }
-
-.. http:post:: /admin/ebics/bank-accounts
-
- Associates a new bank account to an existing subscriber.
-
- **Request:**
-
- .. ts:def:: BankAccountRequest
-
- interface BankAccountRequest {
-
- // Ebics subscriber
- subscriber: string;
-
- // IBAN
- iban: string;
-
- // BIC
- bic: string;
-
- // human name
- name: string;
-
- // bank account label
- label: string;
-
- }
-
-..
- Main EBICS service.
-
-.. http:post:: /ebicsweb
-
- Serves all the Ebics requests.
diff --git a/libeufin/bank-manual.rst b/libeufin/bank-manual.rst
new file mode 100644
index 00000000..ab793b2b
--- /dev/null
+++ b/libeufin/bank-manual.rst
@@ -0,0 +1,307 @@
+..
+ This file is part of GNU TALER.
+ Copyright (C) 2014-2024 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Florian Dold
+ @author Marcello Stanisci
+ @author Christian Grothoff
+
+.. target audience: operator, developer
+
+.. _libeufin-bank:
+
+Bank Setup Manual
+#################
+
+libeufin-bank implements a simple core banking system with
+account and REST APIs, including REST APIs for a Web interface
+and REST APIs to interact with GNU Taler components.
+
+In this manual, we explain how to setup a bank.
+
+.. contents:: Table of Contents
+ :local:
+
+
+Installing LibEuFin Bank
+========================
+
+The following section was tested on an *OpenJDK 17* environment.
+
+Installing the libeufin-bank binary packages on Debian
+------------------------------------------------------
+
+.. include:: ../frags/installing-debian.rst
+
+.. include:: ../frags/apt-install-libeufin-bank.rst
+
+
+Installing the libeufin-bank binary packages on Ubuntu
+------------------------------------------------------
+
+.. include:: ../frags/installing-ubuntu.rst
+
+.. include:: ../frags/apt-install-libeufin-bank.rst
+
+
+Building from source
+--------------------
+
+Bank belongs to the LibEuFin project, and can be downloaded via Git:
+
+.. code-block:: console
+
+ $ git clone git://git.taler.net/libeufin
+
+Note that Kotlin and Gradle should already work on the host system.
+
+Navigate into the *libeufin* local repository, and from top-level run:
+
+.. code-block:: console
+
+ $ ./bootstrap
+ $ ./configure --prefix=$PREFIX
+ $ make install
+
+If the previous steps succeeded, the ``libeufin-bank`` command should
+be found in the $PATH.
+
+
+Minimal Configuration for LibEuFin Bank
+=======================================
+
+The following snippet shows the mandatory configuration values:
+
+.. code-block:: ini
+
+ [libeufin-bank]
+ CURRENCY = KUDOS
+
+ # Supported payment target type
+ WIRE_TYPE = iban or x-taler-bank
+ # If WIRE_TYPE = iban
+ IBAN_PAYTO_BIC = SANDBOXX
+ # If WIRE_TYPE = x-taler-bank
+ X_TALER_BANK_PAYTO_HOSTNAME = https://bank.taler.net
+
+.. note::
+ Refer to the manpage ``libeufin-man.conf(5)``
+ for the full array of configuration values.
+
+.. _libeufin-mfa:
+
+Configuring multi-factor authentication
+---------------------------------------
+
+libeufin-bank supports two-factor authentication. libeufin-bank uses helper scripts to send challenge codes to addresses for multi-factor authentication. We provide two default helper scripts: ``libeufin-tan-email.sh`` to send e-mails and ``libeufin-tan-sms.sh`` to send SMS. To enable two-factor authentication you need to configure at least one TAN channel.
+
+SMS TAN channel
++++++++++++++++
+
+The default ``libeufin-tan-sms.sh`` script is based on the `Telesign <https://www.telesign.com>`_ SMS provider. It requires an additional ``AUTH_TOKEN`` environment variable for `Telesign Basic authentication <https://developer.telesign.com/enterprise/docs/authentication#basic-authentication>`_.
+
+To test your setup run:
+
+.. code-block:: console
+
+ $ AUTH_TOKEN=$TELESIGN_TOKEN
+ $ echo "Test 1234" | libeufin-tan-sms.sh $PHONE
+
+If you received an SMS containing "Test 1234" you can enable this channel in the config:
+
+.. code-block:: ini
+
+ [libeufin-bank]
+ TAN_SMS = libeufin-tan-sms.sh
+ TAN_SMS_ENV = "AUTH_TOKEN=$TELESIGN_TOKEN"
+
+Mail TAN channel
+++++++++++++++++
+
+The default ``libeufin-tan-email.sh`` script is based on the ``mail`` Linux command. It requires a working local mail transfer agent.
+
+To test your setup run:
+
+.. code-block:: console
+
+ $ echo "Test 1234" | libeufin-tan-email.sh $EMAIL
+
+If you received an email containing "Test 1234" you can enable this channel in the config:
+
+.. code-block:: ini
+
+ [libeufin-bank]
+ TAN_EMAIL = libeufin-tan-email.sh
+
+Custom TAN channel scripts
+++++++++++++++++++++++++++
+
+It is possible to replace these scripts with use custom scripts to send
+the e-mail or SMS TAN. Such alternative scripts must accept the phone number / e-mail address as the ``$1`` parameter and the message content to be transmitted in their standard input. They should return 0 to indicate successful transmission of the challenge and non-zero on failure.
+
+To change the scripts used for multi-factor authentication, change the following
+options in the configuration file:
+
+.. code-block:: ini
+
+ [libeufin-bank]
+ TAN_SMS = custom-tan-sms.sh
+ TAN_SMS_ENV =
+ TAN_EMAIL = custom-tan-email.sh
+ TAN_EMAIL_ENV =
+
+Launching libeufin-bank
+=======================
+
+Assuming that the configuration file exists at ``$CONFIG_FILE``, the following
+command initializes (or upgrades) the database schema:
+
+.. code-block:: console
+
+ $ libeufin-bank-dbinit -c "$CONFIG_FILE"
+
+Once this is done, you can start the libeufin-bank HTTP server:
+
+.. code-block:: console
+
+ $ libeufin-bank serve -c "$CONFIG_FILE"
+
+
+
+Using the bank Web interface
+============================
+
+To be able to use the Web interface, you must set a password for the "admin"
+account. You can set (or reset) the account password to ``$PASSWORD`` using
+the following command:
+
+.. code-block:: console
+
+ $ libeufin-bank passwd -c "$CONFIG_FILE admin "$PASSWORD"
+
+You can also use the same command to reset the passwords of other accounts by
+replacing "admin" with the respective login.
+
+
+Setting up accounts
+-------------------
+
+Using the above "$PASSWORD", log into the Web interface as "admin". To setup
+regular accounts, search for the button "Create account" near the list of all
+existing bank accounts in the Web interface of libeufin-bank.
+
+You will be asked to specify:
+
+Username
+ A unique account name the user will use to access the bank account.
+
+Name
+ Legal name of the user or business owning the account.
+
+Email
+ E-mail address of the account owner. Can be used to send a TAN message for 2-factor authentication (if enabled).
+
+Phone
+ Mobile phone number of the account owner. Can be used to send a TAN message for 2-factor authentication (if enabled).
+
+Max debt
+ Maximum amount the account is allowed to go into debt. Non-zero settings **must** be used for the "admin" account where this setting effectively creates a limit on the amount of money managed by the bank.
+
+Is this a Taler Exchange?
+ Should be disabled except if you are setting up an account for a GNU Taler exchange. If enabled, transactions that are not compatible with a GNU Taler exchange will be automatically refused by the bank.
+
+XXX Cashout channel
+ Used in a regional currency setup to specify the external account number of a bank account in fiat currency that belongs the merchant. Allows the merchant to exchange its regional currency money for wire transfers in fiat currency into this account. Optional. Not available unless the bank is configured for regional currencies.
+
+Is this account public?
+ Public accounts can be viewed without access control, their balance and transaction history becomes public.
+
+After submitting the form, a randomly created password for the new account
+will be shown in a notification. The administrator can also change passwords
+for any account in the system using the "change password" link in the account
+list. To change other details about an account, select the "Username" in the
+account list.
+
+
+Account introspection
+---------------------
+
+Users can see (and possibly change) the settings of their bank account and
+also their IBAN by clicking on the "Welcome, $USERNAME" text after logging
+into their bank account using their username and password.
+
+The IBAN field has a convenient "copy to clipboard" button next to it.
+
+
+Making transfers between accounts
+---------------------------------
+
+First, you need to know the IBAN of the account to credit, and log in as the
+user of the account to be debited. Then select "Using a form", enter the IBAN
+under "Recipient" and specify a wire transfer subject and the total amount to
+be wired. After pressing "Send", you may have to pass a 2-FA check.
+
+
+Integration with the Taler Exchange
+===================================
+
+.. note::
+
+ This step is fully automated if you use the :doc:`automated setup manual<regional-automated-manual>`.
+
+You must have an exchange account with username ``exchange`` for conversion to work.
+Assuming that the configuration file exists at ``$CONFIG_FILE``, the following
+command would create one:
+
+.. code-block:: console
+
+ $ libeufin-bank create-account '{"username":"exchange","password":"$EXCHANGE_PASSWORD","name":"Cashout Exchange","is_taler_exchange":true}' -c "$CONFIG_FILE"
+
+.. note::
+
+ You can also set up the exchange account as "admin" using the Web interface of libeufin-bank.
+
+Having done so, take note of two key pieces of information, namely the ``$EXCHANGE_PASSWORD`` and the "payto://"-URI of the exchange bank account. This information must then be used to configure the exchange as described in
+:ref:`exchange bank account configuration <exchange-account-signing>`. When using the libeufin-bank in the context
+of a regional currency with conversion, you must
+additionally specify a "conversion-url" when setting
+up the exchange account. See the section on :ref:`conversion setup <regional-conversion-setup>` in the regional currency setup chapter for details.
+
+
+Withdrawing e-cash to a Taler wallet
+====================================
+
+.. note::
+
+ This step is fully automated if you use the :doc:`automated setup manual<regional-automated-manual>`.
+
+Users can withdraw digital cash from their bank account starting from their
+online banking as implemented by the libeufin-bank. However, in this scenario,
+the Taler wallet may not already know about an exchange that works with the
+respective currency. Thus, the protocol includes the possibility of the bank
+*recommending* an exchange service to the wallet, thus providing a sane
+default for the wallet to suggest to the user. To do so, the base URL of the
+exchange API must be specified in the libeufin-bank configuration:
+
+.. code-block:: ini
+
+ [libeufin-bank]
+ DEFAULT_EXCHANGE=${PROTO}://exchange.${DOMAIN_NAME}
+
+After changing this value, the libeufin-bank service needs to be restarted
+to make the change effective.
+
+.. note::
+
+ The user may change the default exchange from within the wallet, assuming they know of an alternative exchanges for the currency.
diff --git a/libeufin/bank-transport-ebics.rst b/libeufin/bank-transport-ebics.rst
deleted file mode 100644
index 7d26cbc3..00000000
--- a/libeufin/bank-transport-ebics.rst
+++ /dev/null
@@ -1,55 +0,0 @@
-.. target audience: core developer
-
-The EBICS Bank Transport
-========================
-
-An EBICS bank transport in LibEuFin conceptually corresponds
-to the "EBICS Subscriber" in EBICS terminology.
-
-
-Bank Transport Setup
---------------------
-
-The following steps are required to set up an EBICS bank transport:
-
-1. The bank must set up the EBICS access for the user.
- The bank will notify the user of the following parameters:
-
- * the URL of the EBICS server used by the bank
- * the HostID of the bank within the EBICS server (sometimes one EBICS server hosts multiple banks)
- * the PartnerID (typically identifies the owner of the bank account within the banking system)
- * the UserID (typically identifies the person that accesses the bank account, can be different from the owner)
- * the SystemID (optional and rarely used, basically a "sub-identity" of a subscriber when multiple technical
- systems have access to the account via EBICS)
-
-2. The user enters the information from the list above in the setup dialog in the LibEuFin nexus (UI/CLI).
-
-3. The LibEuFin nexus generates cryptographic key material (3 RSA key pairs).
-
-4. The nexus sends the public keys electronically to the bank's EBICS server, together with the information
- identifying the subscriber (PartnerID, UserID, SystemID).
-
-5. The user prints a document that contains the public key and hashes for all three key pairs.
- The user then signs this document and sends it to the bank (physically/scanned).
-
-6. The bank receives the letter and verifies that the keys from the letter correspond
- to the electronically sent keys. If they match, the bank sets the state of the
- subscriber to "ready".
-
-7. The user now has to wait until the bank has set the EBICS subscriber state to "ready".
- There is no in-band notification for this, but the Nexus can try downloading the bank's
- cryptographic parameters. This will only succeed once the EBICS subscriber is set to "ready"
- by the bank.
-
-8. The user should confirm the public keys of the bank received in the previous step.
- Typically the bank gives the value of these public keys in an out-of-band channel.
-
-9. Now the user can finally use the EBICS bank transport. The first step after finishing
- the setup should be to import the bank accounts accessible for this EBICS subscriber.
-
-
-Alternative ways of setting up the EBICS bank transport are:
-
-* Importing from a backup. The backup contains metadata (EBICS URL, HostID,
- UserId, ...) and the three passphrase-protected subscriber keys.
-* Certificate-based setup (currently not supported by LibEuFin, only used in France)
diff --git a/libeufin/banking-protocols.rst b/libeufin/banking-protocols.rst
deleted file mode 100644
index 2eaffb3d..00000000
--- a/libeufin/banking-protocols.rst
+++ /dev/null
@@ -1,127 +0,0 @@
-.. target audience: core developer
-
-Banking Protocols
-#################
-
-This page collects information we have about banking protocols available around
-the world.
-
-
-Open Financial Exchange (OFX) Direct Connect
-============================================
-
-`OFX <https://www.ofx.net/>`__ is widely used in the US. It defines a completely
-custom protocol (based on HTTP) and data formats (**not** based on ISO20022) for banking.
-
-
-Electronic Banking Internet Communication Standard (EBICS)
-==========================================================
-
-EBICS is used primarily in Germany, France and Switzerland. Some banks (such as BNPParibas
-with their `Global Ebics <https://cashmanagement.bnpparibas.com/our-solutions/solution/global-ebics>`__)
-also allow EBICS access to accounts in other countries.
-
-EBICS is just a transfer layer for communicating with banks. Banks define what
-messages they support. In practice, EBICS is very often used to transfer
-ISO20022 messages.
-
-German banks that are part of the German Banking Industry Committee all must offer EBICS access.
-Thus this protocol is a good choice for the German market.
-
-
-FinTS / HBCI
-============
-
-German home-banking standard. FinTS is the successor of the Home Banking
-Computer Interface (HBCI), but older versions of FinTS are often still called
-HBCI.
-
-The current version, FinTS 4.0, is not widely supported by banks yet. Starting with FinTS,
-XML is used as a data format. Previous versions used a custom text/binary format.
-
-Only some banks allow authentication based on key pairs.
-Due to different interpretation of PSD2, other banks now only allow authentication
-methods that require interaction from the customer (SCA / Strong Customer Authentication).
-
-Payloads these days can be ISO20022 messages.
-
-Examples:
- * `GLS <https://www.gls.de/geschaefts-firmenkunden/zahlungsverkehr/onlinebankingverfahren-und-programme/daten-zum-onlinebanking/>`__
-
-
-PSD2
-====
-
-PSD2 is not a technical standard, but high-level legal requirements on (amongst other things) APIs
-that banks have to offer.
-
-There are many implementations of PSD2 APIs. The `Berlin Group <https://www.berlin-group.org/>`__
-provides a framework that somewhat standardizes technical details, but the use of this standard
-is by no means necessary.
-
-Unfortunately, it focuses on *other* parties accessing *your* bank account. It
-does not give customers access to their own bank account. Customers can manage
-third party access they give to their bank account in their online banking
-system. That mechanism is conceptually similar to OAuth2. In fact, some
-implementations of PSD2 even use OAuth2 directly.
-
-PSD2 APIs usually use JSON as a data format. Often the schema and terminology is "inspired" by ISO20022
-messages, but no actual ISO20022 XML message formats are used.
-
-PSD2 requires two main services to be available via an API:
-
-* AIS (Account Information Service).
-* PIS (Payment Initiation Service).
-
-Together, they're often called XS2A ("access to account").
-
-An entity that wants to use AIS has to be registered with the financial
-oversight authority in its country (BAFIN in Germany). PIS has even stronger
-legal prerequisites.
-
-On a technical level, using PSD2 APIs usually requires having an `EIDAS <https://en.wikipedia.org/wiki/EIDAS>`__ certificate.
-
-Examples (bank offerings):
- * `Sparkasse <https://xs2a.sparkassen-hub.com/home>`__ (Berlin Group based)
- * `Deutsche Bank <https://developer.db.com/products/psd2>`__
-
-Examples (standards):
- * `STET PSD2 API <https://www.stet.eu/en/psd2/>`__
- * `Berlin Group NextGenPSD2 <https://www.berlin-group.org/nextgenpsd2-downloads>`__
-
-
-
-Bank-Proprietary APIs
-=====================
-
-Some banks offer completely custom APIs to access services of the bank. These often include services
-not available via more standardized APIs, such as account creation.
-
-Often banks frame PSD2 as just another API available in their portfolio of API offerings.
-
-Examples:
-
-* `Deutsche Bank <https://developer.db.com/products>`__
-* `ING Group <https://developer.ing.com/api-marketplace/marketplace>`__
-* `Revolut <https://revolut-engineering.github.io/api-docs/business-api/>`__
-* `PayPal <https://developer.paypal.com/classic-home/>`__
-
-
-Open Bank Project
-=================
-
-The `Open Bank Project <https://www.openbankproject.com/>`__ provides a free software implementation of
-banking middleware that supports various APIs, including PSD2-compatible APIs (based on Berlin Group).
-
-API Docs: `<https://github.com/OpenBankProject/OBP-API/wiki/Open-Bank-Project-Architecture>`__
-
-
-UK Open Banking
-===============
-
-Open Banking is the (quite confusing!) name of a UK-based open banking initiative.
-
-What's nice about Open Banking is that their APIs are really close to ISO 20022, unlike many
-similar HTTP+JSON APIs.
-
-`<https://openbanking.atlassian.net/wiki/spaces/DZ/pages/16385802/Specifications>`__
diff --git a/libeufin/camt.054-style-0.png b/libeufin/camt.054-style-0.png
new file mode 100644
index 00000000..05ca6365
--- /dev/null
+++ b/libeufin/camt.054-style-0.png
Binary files differ
diff --git a/libeufin/camt.054-style-1.png b/libeufin/camt.054-style-1.png
new file mode 100644
index 00000000..30f7d535
--- /dev/null
+++ b/libeufin/camt.054-style-1.png
Binary files differ
diff --git a/libeufin/check-payment-subject-0.png b/libeufin/check-payment-subject-0.png
new file mode 100644
index 00000000..eb8c8ca5
--- /dev/null
+++ b/libeufin/check-payment-subject-0.png
Binary files differ
diff --git a/libeufin/check-payment-subject-1.png b/libeufin/check-payment-subject-1.png
new file mode 100644
index 00000000..eb99cf20
--- /dev/null
+++ b/libeufin/check-payment-subject-1.png
Binary files differ
diff --git a/libeufin/concepts.rst b/libeufin/concepts.rst
deleted file mode 100644
index 6a251991..00000000
--- a/libeufin/concepts.rst
+++ /dev/null
@@ -1,166 +0,0 @@
-.. target audience: operator, developer
-
-###################
-Conceptual Overview
-###################
-
-
-What is LibEuFin
-================
-
-The goal of LibEuFin is to make the development and testing of
-FinTech applications easier. It hides implementation details
-of complex legacy banking APIs behind a simple interface.
-
-LibEuFin Nexus and Sandbox
---------------------------
-
-LibEuFin has two main components:
-
-1. The LibEuFin nexus receives banking-related requests in a LibEuFin-specific
- format via an HTTP API. It then translates those requests into interactions
- with other banking APIs, abstracting away different underlying protocols and
- hiding the complexity of the legacy protocols used by some banks.
-
-2. The LibEuFin sandbox implements the server side of protocols
- that banks speak. It also emulates a *very*, *very* simple
- core banking system to manage accounts and their balance.
- The main use case for the sandbox is testing LibEuFin itself,
- as well as applications developed with LibEuFin.
- The sandbox has a JSON API to set it up for tests (creating bank
- hosts, bank accounts, fake transactions).
-
-
-High-Level Concepts
-===================
-
-Nexus Users
------------
-
-The concept of a *nexus user* is used to implement access control to the
-operations that the nexus provides.
-
-A user has a login name and a (salted, hashed) password.
-This is the `HTTP basic auth <https://tools.ietf.org/html/rfc7617>`_ method.
-(Other authentication methods could be added in the future.)
-
-A nexus user can be marked as *superuser*. All permission checks are skipped
-for superusers. Only superusers are allowed to create/modify other users.
-
-Bank Accounts
--------------
-
-A *bank account* is the local representation of some bank account.
-The information stored about it includes:
-
-* Local alias ("nickname") of the bank account
-* Account identification (IBAN / BIC / account holder)
-* A local mirror of the bank transaction history
-* Payment requests, i.e. payments that have been locally requested, together
- with their state (sent or not sent, acknowledged in bank statement or not)
-* Error reports (e.g. failed payment requests, bank statement items that were not understood
- by LibEuFin)
-* A default bank connection (if configured) that is used by default
- for operations on the account
-* Other enabled "bank connections" (see definition below)
-
-Examples:
-
-.. code-block:: console
-
- # Download latest transactions via the default bank connection and store them locally
- $ http -a $USER:$PASSWORD POST \
- https://example1.libeufin.tech/bank-accounts/my-acct/fetch-transactions
-
-Bank Connections
-----------------
-
-Bank connections connect the local LibEuFin bank account to the real bank.
-The *bank connection* includes the following data:
-
-* Local alias ("nickname") of the bank connection
-* The type of connection, i.e. the protocol used (EBICS, FinTS, loopback, sandbox)
-* Protocol configuration (hostname, port, protocol sub-version/flags)
-* Credentials to use the connection (e.g. password, EBICS subscriber keys)
-
-Bank connections provide the following actions:
-
-* Initial setup of the connection
-
-* Execute protocol-specific actions (e.g. EBICS: C53, C52, CCT, CRZ)
-
- * These actions do not have any effect on the LibEuFin local bank account.
- To persist changes to the local bank account (transaction history, payment request status),
- the bank connection must be invoked via the bank account.
-
-* Import bank accounts
-
- * Some bank connection protocols allow LibEuFin to query a list of bank
- accounts that the connection has access to. This makes setup easier,
- as the user doesn't have to create the local bank account manually.
-
-Examples:
-
-.. code-block:: console
-
- # Manually request the inter-day account report via the EBICS C52 order
- $ http -a $USER:$PASSWORD POST \
- https://example1.libeufin.tech/bank-connections/my-ebics-testacct/ebics/download/C52
-
- # Download available bank accounts that can be accessed through this connection,
- # according to the bank server (with EBICS, does a HTD request).
- # For each of them, create a bank account resource in LibEuFin.
- $ http -a $USER:$PASSWORD POST \
- https://example1.libeufin.tech/bank-connection/my-ebics-testacct/fetch-accounts
-
-Facades
--------
-
-Facades allow extra domain-specific functionality to be implemented on top of users, bank accounts
-and bank connections. A *facade* stores the following information:
-
-* Local name of the facade
-* Facade type and options specific to the type
-* Associated bank accounts and bank connections that can be accessed by the facade
-* Internal tables used by the facade (i.e. facades are stateful)
-
-The only facade currently supported by LibEuFin is the "Taler Wire Gateway API" layer.
-It provides a filtered view on the transaction history, a more restricted API to create payment
-requests, and a mechanism to create a counter-transaction for incoming transactions that do
-not conform to a certain format.
-
-Examples:
-
-.. code-block:: console
-
- # Request the Taler-specific history through the facade
- $ http -a $USER:$PASSWORD \
- https://example1.libeufin.tech/facades/my-taler-wire-gw/taler/history/incoming
-
-Access Control
-==============
-
-The goal of *access control* in LibEuFin is to allow the following scenarios:
-
-* The Nexus can be used by multiple clients for different bank accounts/connections
- and these users can't access each other's bank accounts
-* For monitoring / dashboard (e.g. Taler rejected transactions, blacklists),
- some users should only be able to have read-only access.
-
-It is currently not planned to have more fine-grained permissions, such as
-spending limits or more fine-grained read/write permissions.
-
-Users can be normal users or superusers. Permission checks do not apply to superusers,
-and only superusers can create other users.
-
-Each top-level object (bank account, bank connection, facade) has a list of
-nexus users with write access, and a list of users with read access.
-
-When using a bank connection through a bank account, permission checks must
-succeed for both the bank account and the bank connection.
-
-This works differently for facades: A facade has a set of associated bank connections
-and bank accounts it can access. Permissions on these associated objects
-are checked when the facade is *created*. When invoking operations on the facade,
-the nexus only checks if the current nexus user can access the facade and *not* the
-underlying objects abstracted by the facade.
diff --git a/libeufin/ebics.rst b/libeufin/ebics.rst
deleted file mode 100644
index 058804e1..00000000
--- a/libeufin/ebics.rst
+++ /dev/null
@@ -1,597 +0,0 @@
-.. target audience: core developer
-
-EBICS Implementation Notes
-##########################
-
-.. warning::
-
- This document summarizes and clarifies some aspects of the EBICS protocol
- that are important to LibEuFin. Both version 3.0 and 2.5 are discussed here.
-
- It is not a specification, and it does not replace the official EBICS specification.
-
-.. contents:: Table of Contents
-
-EBICS Glossary
-==============
-
-.. glossary::
- :sorted:
-
- A004
- Electronic signature process, used in :term:`H004`, deprecated in :term:`H005` with EBICS 3.0.
-
- A005
- Electronic signature process. Used in :term:`H004` and :term:`H005`.
-
- A006
- Electronic signature process. Used in :term:`H004` and :term:`H005`.
-
- BTF
- *Business Transaction Formats.* Before EBICS 3.0, many different order types were
- used for business-related messages. With EBICS 3.0, the more generic BTU and BTD
- order types are used for all business-related messages.
-
- EBICS
- The *Electronic Banking Internet Communication Standard*.
-
- ES
- Electronic Signature. This abbreviation is commonly used in the context of EBICS.
-
- The following signature classes are defined (in descending order from
- strongest to weakest):
-
- E
- Single signature (German "Einzeln").
- A
- First signature.
- B
- Second signature.
- T
- Transport signature. Only used to verify authorized submission,
- but not to verify the bank-technical authorization.
-
- In H004 and H005, the ES of the bank is specified as a "planned feature" that
- is not actually implemented yet. Thus banks in practice only use their
- encryption key pair and authentication/identity key pair.
-
- EDS
- Distributed Electronic Signature. Allows multiple subscribers to authorize an existing order.
-
- FTAM
- Historical predecessor protocol to EBICS (*file transfer, access and management*).
-
- HEV
- The *Host EBICS Version*. Queried by the client with an HEV request message.
-
- Human Subscriber
-
- See :term:`Subscriber`.
-
- H004
- Host protocol version 4. Refers to the XML Schema defined in *EBICS 2.5*.
-
- H005
- Host protocol version 5. Refers to the XML Schema defined in *EBICS 3.0*.
-
- Host ID
- Alphanumeric identifier for the EBICS Host. One EBICS server can
- host multiple banks, and each bank is identified by the Host ID.
- This concept is similar to Taler's merchant backend instance identifiers.
-
- Order Number
- Interchangeably called "Order ID".
-
- Each upload transaction gets a unique order number assigned by the bank server.
- The Order Number is used to match VEUs in a second upload to the original order.
- An Order Number matches the format ``[A-Z][A-Z0-9]{3}`` (and is not really a number!).
-
- Must be unique per customer ID and per order type.
-
- Transaction ID
- A transaction ID is a 128-bit cryptographically strong random number.
- It is assigned by the bank server for every transaction, i.e. upload or download
- of an order.
-
- The transaction ID must not be guessable, as it would allow a potential
- attacker to upload segments of an upload that do not match the whole message's digest.
-
- Transaction key
- Symmetric encryption key for the data uploaded/downloaded in a transaction.
-
- Partner ID
- In German, this is called "Kunden ID" (= Customer ID).
- One partner can have multiple "participants", which are identified by user IDs.
-
- Practical example: A company has one Partner ID. Each person at the company
- that can access the company's bank accounts gets their own User ID.
- When the person is indirectly accessing the bank server (for example via
- a client server application), an additional "System ID" is created for this
- "technical subscriber". When there is no technical subscriber, the System ID
- must be the same as the User ID. Usually the System ID is optional though.
-
- The ``(partner, user, system)`` triple uniquely identifies a subscriber.
-
- User ID
- See :term:`Partner ID`.
-
- System ID
- See :term:`Partner ID`.
-
- ISO 20022
- *ISO 20022: Financial Services - Universal financial industry message scheme*. Rather important
- standard for financial industry **business-related** messages. In contrast, EBICS takes
- care of message transmission, segmentation, authentication, key management, etc.
-
- The full catalogue of messages is `available gratis <https://www.iso20022.org/full_catalogue.page>`_.
-
- UNIFI
- UNIversal Financial Industry message scheme. Sometimes used to refer to
- :term:`ISO 20022`.
-
- Segmentation
- EBICS implements its own protocol-level segmentation of business-related messages.
- The segmentation can be seen as an alternative to the HTTP facilities of ``Accept-Ranges``.
-
- The order data of an EBICS message may not exceed 1 MB. The segmentation applies both
- to requests and responses.
-
- Subscriber
- Entity that wishes to communicate with the financial institution via EBICS.
-
- Subscribers can be *technical* or *human*. Technical subscribers are typically
- a server in client-server applications, where the server talks to a financial institution
- via EBICS.
-
- Requests from technical subscribers have a ``SystemID`` in addition to a ``PartnerID``
- and ``UserId``. A technical subscriber cannot sign a bank-technical request.
-
- Technical Subscriber
- See :term:`Subscriber`.
-
- TLS
- *Transport Layer Security*. All messages in EBICS are sent over HTTP with TLS.
- In the current version of the standard, only server certificates are required.
-
- VEU
- Distributed Electronic Signature (from German "Verteilte Elektronische Unterschrift").
-
- V001
- FTAM encryption algorithm ("Verschlüsselung"), superseded in EBICS by E002.
-
- E002
- EBICS encryption process, used to encrypt the order payload.
-
- X002
- Identification and authentication signature in H004 and H005.
-
-
-Order Types
-===========
-
-By convention, order types beginning with "H" are administrative order types, and other ones are
-bank-technical order types. This convention isn't always followed consistently by EBICS.
-
-Relevant Order Types
---------------------
-
-.. ebics:orders::
- :sorted:
-
- BTD
- **Only EBICS3.0+**. Business Transaction Format Download.
- Administrative order type to download a file, described in more detail by the BTF structure.
-
- BTU
- **Only EBICS3.0+**. Business Transaction Format Upload.
- Administrative order type to upload a file, described in more detail by the BTF structure.
-
- C52
- **Before EBICS 3.0**. Download bank-to-customer account report (intra-day information).
-
- C53
- **Before EBICS 3.0**. Download bank-to-customer statement report (prior day bank statement).
-
- CRZ
- Type: Download.
-
- Fetch payment status report (pain.002).
-
- CCC
- Type: Upload.
-
- Send SEPA Credit Transfer Initiation (pain.001) via XML container.
- This is the DFÜ variant (Appendix 3 DFÜ-Agreement).
-
- CCT
- Type: Upload.
-
- Send SEPA Credit Transfer Initiation (pain.001) directly.
- This is the DFÜ variant (Appendix 3 DFÜ-Agreement).
-
- CIZ
- Type: Download.
-
- Payment Status Report for Credit Transfer Instant.
-
- FUL
- **Before EBICS 3.0, France**. File Upload. Mainly used by France-style EBICS.
-
- FDL
- **Before EBICS 3.0, France**. File Download. Mainly used by France-style EBICS.
-
- HAA
- Type: Download, Optional.
-
- Download order types for which there is new data available.
-
- HTD
- Type: Download.
-
- Download information about a subscriber. From German "Teilnehmerdaten".
-
- HKD
- Type: Download, Optional.
-
- Download information about a customer (=partner). From German "Kundendaten".
-
- HIA
- Transmission of the subscriber keys for (1) identification and authentication and (2)
- encryption within the framework of subscriber initialisation.
-
- HPB
- Query the three RSA keys of the financial institute.
-
- HPD
- Host Parameter Data. Used to query the capabilities of the financial institution.
-
- INI
- Transmission of the subscriber keys for bank-technical electronic signatures.
-
- HAC
- Customer acknowledgement. Allows downloading a detailed "log" of the activities
- done via EBICS, in the pain.002 XML format.
-
- HCS
- Change keys without having to send a new INI/HIA letter.
-
- SPR
- From German "sperren". Suspend a subscriber. Used when a key compromise is
- suspected.
-
- HCS
- Change the subscribers keys (``K_SIG``, ``K_IA`` and ``K_ENC``).
-
-Other Order Types
------------------
-
-The following order types are, for now, not relevant for LibEuFin:
-
-
-.. ebics:orders::
- :sorted:
-
- AZV
- Type: Upload.
-
- From German "Auslandszahlungsverkehr". Used to submit
- cross-border payments in a legacy format.
-
- CDZ
- Type: Download.
-
- Download payment status report for direct debit.
-
- CCU
- Type: Upload.
-
- German "Eilüberweisung".
-
- H3K
- Type: Upload.
-
- Send all three RSA key pairs for initialization at once, accompanied
- by a CA certificate for the keys. This is (as far as we know) used in France,
- but not used by any German banks. When initializing a subscriber with H3K,
- no INI and HIA letters are required.
-
- HVE
- Type: Upload.
-
- Host Verification of Electronic Signature. Used to submit an electronic signature separately
- from a previously uploaded order.
-
- HVD
- Type: Download.
-
- Retrieve VEU state.
-
- HVU
- Type: Download.
-
- Retrieve VEU overview.
-
- HVU
- Type: Download.
-
- Retrieve VEU extra information. From German "Zusatzinformationen".
-
- HVS
- Type: Upload.
-
- Cancel Previous Order (from German "Storno"). Used to submit an electronic signature separately
- from a previously uploaded order.
-
- HSA
- Type: Optional
-
- Order to migrate from FTAM to EBICS. **Removed in EBICS 3.0**.
-
- PUB
- Type: Upload.
-
- Change of the bank-technical key (``K_SIG``).
- Superseded by HSA.
-
- HCA
- Type: Upload.
-
- Change the identification and authentication key as well as the encryption key (``K_IA`` and ``K_ENC``).
- Superseded by HCS.
-
- PTK
- Type: Download.
-
- Download a human-readable protocol of operations done via EBICS.
- Mandatory for German banks. Superseded by the machine-readable
- HAC order type.
-
-
-EBICS Message Format
-====================
-
-The following elements are the allowed root elements of EBICS request/response messages:
-
-* ``ebicsHEVRequest`` / ``ebicsHEVResponse``: Always unauthenticated and unencrypted. Used
- **only** for query/response of the host's EBICS version.
-* ``ebicsUnsecuredRequest``: Request without signature or encryption (beyond TLS). Used for INI and HIA.
-* ``ebicsKeyManagementResponse``: Unauthenticated response. Used for key management responses and
- sometimes **also** to deliver error messages that are not signed by the bank (such as "invalid request").
-* ``ebicsNoPubKeyDigestsRequest``: Signed request that *does not* contain the hash of the bank's
- public key that the client expects. Used for key management, specifically only the HPB order type.
-* ``ebicsRequest`` / ``ebicsResponse``
-* ``ebicsUnsignedRequest``: Not used anymore. Was used in FTAM migration with the HSA order type.
-
-
-Order ID Allocation
-===================
-
-In practice, the Order ID seems to be allocated via number of counters at the level of the **PartnerID**.
-
-
-EBICS Transaction
-=================
-
-A transaction in EBICS simply refers to the process of uploading or downloading
-a file. Whether it is an upload or download transaction depends on the order
-type. Each transaction is either an upload transaction or a download
-transaction, neither both.
-
-Uploads and downloads must proceed in segments of at most ``1 MB``. The
-segmentation happens after (1) encryption, (2) zipping, and (3) base64-encoding
-of the order data.
-
-The number of segments is always fixed starting from the first message sent
-(for uploads) or received (for downloads) by the subscriber. The digest of the
-whole message is also sent/received with the first message of a transaction.
-The EBICS host generates a 128-bit transaction ID. This ID is used to
-correlate uploads/downloads of segments for the same transaction.
-
-If an attacker would be able to guess the transaction ID, they could upload a
-bogus segment. This would only be detected after the whole file has been
-transmitted.
-
-An upload transaction is finished when the subscriber has sent the last
-segment. A download transaction is only finished when the subscriber has sent
-an additional acknowledgement message to the EBICS host.
-
-When upload/download of a segment fails, the client can always re-try. There
-are some conditions for that:
-
-* Segment ``n`` can only be downloaded/uploaded when segments ``[0..n-1]`` have
- been downloaded/uploaded.
-* The (implementation-defined) retry limit may not be exceeded.
-
-
-Formats
-=======
-
-ISO 20022
----------
-
-ISO 20022 is XML-based and defines the message format for many finance-related activities.
-
-ISO 20022 messages are identified by a message identifier in the following format:
-
- <business area> . <message identifier> . <variant> . <version>
-
-Some financial instututions (such as the Deutsche Kreditwirtschaft) may decided to use
-a subset of elements/attributes in a message, this is what the ``<variant>`` part is for.
-"Standard" ISO20022 have variant ``001``.
-
-The most important message types for LibEuFin are:
-
-camt - Cash Management
- Particularly camt.053 (BankToCustomerStatement)
-
-pain - Payment Initiation
- Particularly pain.001 (CustomerCreditTransferInitiation) to initiate a payment and
- pain.002 (CustomerPaymentStatus) to get the status of a payment.
-
-
-SWIFT Proprietary
-=================
-
-SWIFT Proprietary messages are in a custom textual format.
-The relevant messages are MT940 and MT942.
-
-* MT940 contains *pre-advice*, in the sense that transactions in it might still
- change or be reversed.
-* MT942 contains the settled transactions by the end of the day.
-
-SWIFT will eventually transition from MT messages to ISO20022,
-but some banks might still only give us account statements in the old
-SWIFT format.
-
-
-
-Key Management
-==============
-
-RSA key pairs are used for three purposes:
-
-1. Authorization of requests by signing the order data. Called the *bank-technical key pair*,
- abbreviated here as ``K_SIG``.
-2. Identification/authentication of the subscriber. Called the *identification and authentication key pair*,
- abbreviated here as ``K_IA``.
-3. Decryption of the symmetric key used to decrypt the bank's response. Called the *encryption key pair*,
- abbreviated here as ``K_ENC``.
-
-One subscriber *may* use three different key pairs for these purposes.
-The identification and authentication key pair may be the same as the encryption key pair.
-The bank-technical key pair may not be used for any other purpose.
-
-
-Real-time Transactions
-======================
-
-Real-time transactions will be supported with EBICS starting November 2019.
-That's the earliest date, some banks may offer it later or not at all.
-
-For us, :ebics:order:`CIZ` is the relevant order type that we need to ask banks
-for.
-
-
-Payment Reversal
-================
-
-It looks like there is no way to "reject" payments, unless you are the bank.
-
-There is a concept of payment reversal (with ``pain.007`` for direct debit and ``camt.055`` for SEPA Credit Transfer),
-but they are a way for the *payer / sender* to reverse a payment before it is finalized.
-
-
-Bank Support
-============
-
-All German banks that are part of the Deutsche Kreditwirtschaft *must* support EBICS.
-
-The exact subset of EBICS order types must be agreed on contractually by the bank and customer.
-The following subsections list the message types that we know are supported by particular banks.
-
-GLS Bank
---------
-
-According to publicly available `forms
-<https://www.gls-laden.de/media/pdf/f1/c6/f2/nderungsauftrag.pdf>`_, GLS Bank
-supports the following order types:
-
-* :ebics:order:`AZV`
-* :ebics:order:`PTK`
-* :ebics:order:`CDZ`
-* :ebics:order:`CRZ`
-* :ebics:order:`CCC`
-* :ebics:order:`CCT`
-* :ebics:order:`CCU`
-* :ebics:order:`HVE`
-* :ebics:order:`HVS`
-* ... and mandatory administrative messages
-
-Sparkasse München
------------------
-
-See `this document <https://www.sskm.de/content/dam/myif/ssk-muenchen/work/dokumente/pdf/allgemein/ebics-default-geschaeftsvorfaelle.pdf>`__.
-
-
-HypoVereinsbank
----------------
-
-See `this document <https://www.hypovereinsbank.de/content/dam/hypovereinsbank/shared/pdf/Auftragsarten_Internet_Nov2018_181118.pdf>`__.
-
-
-Cryptography
-============
-
-EBICS uses the XML Signature standard for signatures. It does *not* use XML encryption.
-
-The EBICS specification doesn't directly reference the standardized URIs for the various
-signing algorithms. Some of these URIs are defined
-in `RFC 6931 <https://tools.ietf.org/html/rfc6931>`__.
-
-* A005 is `<http://www.w3.org/2001/04/xmldsig-more#rsa-sha256>`__.
-
- * The ``RSASSA-PKCS1-v1_5`` signature scheme contains the ``EMSA-PKCS1-v1_5`` encoding scheme
- mentioned in the EBICS spec.
-
-* A006 is `<http://www.w3.org/2007/05/xmldsig-more#rsa-pss>`__ as defined in RFC 6931.
-
-XML Signatures
---------------
-
-XML Signatures can be a combination of:
-
-* detached (referencing another document)
-* enveloping (signs over ``Object`` tags *within* the ``Signature`` elements)
-* enveloped (signs over arbitrary data (via XPath expression) in other parts of the document
- that contains the signature).
-
-In EBICS, only **enveloped** signatures are used.
-
-In the XML Signature standard, the element for a signature is ``Signature``. EBICS violates this
-standard by always mandating ``AuthSignature`` as the name. ``AuthSignature`` is an alias to
-the ``SignatureType`` XSD type in the XML Schema.
-
-Canonicalization vs transforms:
- * Canonicalization refers to the processing of the ``SignedInfo`` element.
- * Transformations apply to the data that ``Reference`` elements reference. Canonicalization
- algorithms can be used as a transformation on referenced data.
-
-Standards and Resources
-=======================
-
-EBICS
------
-
-The EBICS standard documents are available at `<http://www.ebics.org>`_.
-
-EBICS 3.0:
-
-* The main EBICS 3.0 specification
- (``2017-03-29-EBICS_V_3.0-FinalVersion.pdf``).
-* Annex 1 specifies EBICS return codes, as EBICS doesn't use HTTP status codes directly
- (``2017-03-29-EBICS_V_3.0_Annex1_ReturnCodes-FinalVersion.pdf``) .
-* Annex BTF contains the registry of BTF codes.
-
-DFÜ Agreement
--------------
-
-The DFÜ Agreement is the set of standards used by the German Banking Industry Committee (Deutsche Kreditwirtschaft).
-
-The following Annexes (also see the `DK Website <https://die-dk.de/zahlungsverkehr/electronic-banking/dfu-verfahren-ebics/>`_) are
-relevant for implementing EBICS:
-
-* Annex 1 is the EBICS specification
-* (Annex 2 is deprecated)
-* Annex 3 describes the data formats used by German banks within EBICS.
-
-EBICS Compendium
-----------------
-
-The `EBICS Compendium <https://www.ppi.de/en/payments/ebics/ebics-compendium/>`_ has some additional info on EBICS.
-It is published by a company that sells a proprietary EBICS server implementation.
-
-Others
-------
-
-* `<https://wiki.windata.de/index.php?title=EBICS-Auftragsarten>`_
-* `<https://www.gls-laden.de/media/pdf/f1/c6/f2/nderungsauftrag.pdf>`_
diff --git a/libeufin/enable-EBICS.png b/libeufin/enable-EBICS.png
new file mode 100644
index 00000000..db2f3f03
--- /dev/null
+++ b/libeufin/enable-EBICS.png
Binary files differ
diff --git a/libeufin/frontend.rst b/libeufin/frontend.rst
deleted file mode 100644
index 1fe1c83f..00000000
--- a/libeufin/frontend.rst
+++ /dev/null
@@ -1,47 +0,0 @@
-.. target audience: core developer
-
-###################
-LibEuFin Frontend
-###################
-
-Introduction
-================
-
-LibEuFin Frontend is a Single Page Application (SPA) built using React that facilitates setting up access to bank accounts, querying/displaying the transaction history of bank accounts and initiating payments.
-
-Architecture
-===============
-
-The frontend code sits in the */frontend* folder. Files in the subfolders are highlighted below.
-
-/actions, /reducers folder
---------------------------
-Contains code that uses Redux to store the login state. Prevents user from relogging in every time they closed the browser or browser tab.
-
-/routes folder
---------------
-Directs the user to the respective pages according to the URL route. Routes are broken down into *UnauthenticatedRoute* and *AuthenticatedRoute*, which corresponds to the user's login state.
-
-/components/login
------------------
-The login page for the user.
-
-/components/navbar
-------------------
-Reusable navbar component that appears on every page of the project.
-
-/components/footer
-------------------
-Reusable footer component that appears on every page of the project.
-
-components/home
----------------
-The home page showing general information of the users for e.g. bank accounts set up.
-
-/components/activity
---------------------
-Shows activity of payments and its transaction history (WIP).
-
-/components/bank-accounts
--------------------------
-Shows bank accounts that are imported. A bank account drawer is shown to facilitate setting up of bank accounts. Each bank account is displayed in a card to display extra details for e.g its print document.
diff --git a/libeufin/get-EBICS-IDs-0.png b/libeufin/get-EBICS-IDs-0.png
new file mode 100644
index 00000000..d64bfba5
--- /dev/null
+++ b/libeufin/get-EBICS-IDs-0.png
Binary files differ
diff --git a/libeufin/get-EBICS-IDs-1.png b/libeufin/get-EBICS-IDs-1.png
new file mode 100644
index 00000000..07cc2681
--- /dev/null
+++ b/libeufin/get-EBICS-IDs-1.png
Binary files differ
diff --git a/libeufin/index.rst b/libeufin/index.rst
index 4141f44b..c77255b0 100644
--- a/libeufin/index.rst
+++ b/libeufin/index.rst
@@ -1,19 +1,34 @@
+..
+ This file is part of GNU TALER.
+ Copyright (C) 2014-2023 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Florian Dold
+ @author Marcello Stanisci
+ @author Christian Grothoff
+
+
LibEuFin
########
LibEuFin is a project providing free software tooling for European FinTech.
.. toctree::
+ :maxdepth: 1
:glob:
- concepts
- bank-transport-ebics
- api-nexus
- api-sandbox
- ebics
- sepa
- iso20022
- banking-protocols
- transaction-identification
- frontend
- nexus-tutorial
+ nexus-manual
+ bank-manual
+ regional-automated-manual
+ regional-custom-manual
+ setup-ebics-at-postfinance
diff --git a/libeufin/iso20022.rst b/libeufin/iso20022.rst
deleted file mode 100644
index a4c0bf7b..00000000
--- a/libeufin/iso20022.rst
+++ /dev/null
@@ -1,213 +0,0 @@
-.. target audience: core developer
-
-ISO 20022
-#########
-
-ISO 20022 is the standard that defines many XML messages for FinTech. It is
-very general, and often countries/orgs define subsets (TVS, technical
-validation subset) of the schema.
-
-Documentation for message fields can be viewed at `<https://www.iso20022.org/standardsrepository>`__.
-
-The primary syntax for ISO 20022 messages is XML. To avoid LibEuFin clients
-having to deal with XML, we define a mapping from ISO 20022 messages into JSON.
-
-The specifics of this mapping are:
-
- * The JSON should be "idiomatic" and easy to process.
- * When possible, the highly nested structures of ISO 20022 should be flattened.
- * It must be possible round-trip between the LibEuFin JSON and ISO 20022
- XML messages. The mapping of message types is not 1-to-1, as some ISO 20022 messages are
- very similar and can be mapped to the same JSON structure.
- * JSON-mapped messages are not explicitly versioned. Instead, changes
- are made in a backwards-compatible way, possibly preserving old versions
- of message elements in the same schema.
-
-
-Why does LibEuFin not use ISO 20022?
-====================================
-
-While LibEuFin can ingest ISO 20022 messages (camt.05x, pain.002) and generate
-them (pain.001), it does not use ISO 20022 in its API and internal data model.
-
-Reasons for not using ISO 20022 directly are:
-
-1. Impedance mismatch. ISO 20022 messages do not map well to query/response
- APIs.
-2. Cumbersome to use. Even when ISO 20022 messages are directly mapped
- to JSON, they are difficult to use due to their verbosity.
-3. Underspecification. Messages like camt.05x leave many "degrees of freedom"
- when translating the underlying data into a message.
-4. No interoperability. As a result of underspecification, different countries/organizations
- define their own subset and interpretation rules for ISO 20022 messages. This can
- lead to even contradictory usage rules. An example for this is how the Swiss and EPC
- interpretations handle transaction amounts in the presence of multiple currencies.
-5. Redundancy. ISO 20022 are redundant, and often mix aspects of the "presentation logic"
- with the underlying data model. An example of this is the optional "summary" information
- in camt.05x messages.
-
-Instead of using ISO 20022 messages directly, LibEuFin leverages the standard in other ways:
-
-* As the data exchange format with banks
-* As a guideline for naming in data formats
-* As a guideline for which concepts need to be understood by LibEuFin
-
-
-Implementation notes for camt.05x
-=================================
-
-Types of amounts in camt messages
----------------------------------
-
-* Entry amount
-
- * ISO 20022: Mandatory, with debit/credit indicator. Indicates money
- moving in/out of the account in the account's currency.
- * LibEuFin: Same.
-
-* Entry transaction amount
-
- * ISO 20022: Optional, direction-less. Amount of money
- moving between the debtor and creditor bank, may not be
- in the account's currency (but the "native" currency between
- the two banks).
- * LibEuFin: Same.
-
-* Entry instructed amount
-
- * ISO 20022: Optional, direction-less. Amount of money specified in the
- payment initiation message. Usually only specified when the amount is in a
- different currency than the account currency.
- * LibEuFin: Same.
-
-* Entry counter value amount
-
- * ISO 20022: Optional, direction-less. Amount in the account's
- currency before charges.
- * LibEuFin: Same.
-
-* Entry announced posting amount
-
- * (not used by LibEuFin)
-
-* EntryDetails amount
-
- * ISO 20022: Optional, with debit-credit indicator. Same as "Entry amount"
- but for EntryDetails (= logical transactions).
- * LibEuFin: Always present. In Swiss camt messages, the element is always
- present. In German/Swedish/... camt, we take the "Entry amount" for
- non-batch entries, whereas in batch entries we use the "EntryDetails
- transaction amount" with the same debit credit indicator as the whole
- entry, which by local rules is always in the bank account currency.
-
-* EntryDetails (transaction / instructed / counter value) amount
-
- * ISO 20022: Optional, direction-less. Same as "Entry ... amount"
- but for EntryDetails (= logical transactions).
- * Same.
-
-* EntryDetails announced posting amount
-
- * (not used by LibEuFin)
-
-
-LibEuFin schema for account history
------------------------------------
-
-FIXME: This is not complete yet.
-
-.. code-block:: typescript
-
- interface NexusTransactionsReponse {
- entries: NexusAccountEntryItem[];
- }
-
- interface NexusAccountEntryItem {
- nexusEntryId: string;
-
- // Serial number that will increase with each update
- // to the entry.
- nexusStatusSequenceId: number;
-
- entry: AccountEntryItem;
- }
-
- interface AccountEntryItem {
-
- // At least one of entryId or accountServicerRef
- // must be non-null
- entryId?: string;
- accountServicerRef?: string;
-
- creditDebitIndicator: "credit" | "debit";
- amount: string;
- currency: string;
- instructedAmountDetails?: {
- amount: string;
- currency: string;
- currencyExchange?: {
- sourceCurrency: string;
- targetCurrency: string;
- unitCurrency: string;
- exchangeRate: string;
- contractId: string;
- quotationDate: string;
- };
- };
- status: "booked" | "pending" | "info";
- valueDate?: string;
- bookingDate?: string;
- mandateId?: string;
- endToEndId?: string;
- messageId?: string;
-
- creditor?: Party
- creditorAgent?: FinancialInstitution;
- creditorAccount?: FinancialInstitution;
-
- debtor?: Party
- debtorAgent?: FinancialInstitution;
- debtorAccount?: FinancialInstitution;
-
- unstructuredRemittanceInformation?: string;
- bankTransactionCode: BankTransactionCode;
- }
-
- interface Party {
- name?: string;
- partyType: "private" | "organization";
- otherId?: {
- id: string;
- schemeName?: string;
- issuer?: string;
- };
- }
-
- interface Account {
- name?: string;
- currency?: string;
- otherId?: {
- id: string;
- schemeName?: string;
- issuer?: string;
- };
- }
-
- interface FinancialInstitution {
- type: "financial-institution";
- name?: string;
- bic?: string;
- otherId?: {
- id: string;
- schemeName?: string;
- issuer?: string;
- };
- }
-
- interface BankTransactionCode {
- domain?: string;
- family?: string;
- subfamily?: string;
- proprietaryIssuer?: string;
- proprietaryCode?: string;
- }
diff --git a/libeufin/nexus-manual.rst b/libeufin/nexus-manual.rst
new file mode 100644
index 00000000..de2f4bae
--- /dev/null
+++ b/libeufin/nexus-manual.rst
@@ -0,0 +1,277 @@
+..
+ This file is part of GNU TALER.
+ Copyright (C) 2014-2024 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Florian Dold
+ @author Marcello Stanisci
+ @author Christian Grothoff
+
+.. target audience: operator, developer
+
+.. _libeufin-nexus:
+
+Nexus Manual
+############
+
+LibEuFin Nexus is an EBICS facilitator. It offers a command line interface to
+setup EBICS access, download banking records, and submit payments. Today, the
+LibEuFin implementation supports EBICS 2.5 and 3.0 and has been tested with
+the Postfinance (CHF). Please note that banks tend to have their own dialects
+of finance messages and thus other retail banks may or may not work. Contact
+us if you need support for another bank or core banking protocol.
+
+Future versions will offer a Web API to allow Taler exchanges to talk to their
+banks.
+
+In this manual, we explain how to setup an EBICS subscriber. We assume that
+the bank has already granted EBICS access to the subscriber.
+
+.. contents:: Table of Contents
+ :local:
+
+
+Installing Nexus
+================
+
+The following section was tested on an *OpenJDK 17* environment.
+
+
+Installing the libeufin-nexus binary packages on Debian
+-------------------------------------------------------
+
+.. include:: ../frags/installing-debian.rst
+
+.. include:: ../frags/apt-install-libeufin-nexus.rst
+
+
+Installing the libeufin-nexus binary packages on Ubuntu
+-------------------------------------------------------
+
+.. include:: ../frags/installing-ubuntu.rst
+
+.. include:: ../frags/apt-install-libeufin-nexus.rst
+
+
+Building from source
+--------------------
+
+Nexus belongs to the LibEuFin project, and can be downloaded via Git:
+
+.. code-block:: console
+
+ $ git clone git://git.taler.net/libeufin
+
+Note that Kotlin and Gradle should already work on the host system.
+
+Navigate into the *libeufin* local repository, and from top-level run:
+
+.. code-block:: console
+
+ $ ./bootstrap
+ $ ./configure --prefix=$PREFIX
+ $ make install
+
+If the previous steps succeeded, the ``libeufin-nexus`` command should
+be found in the $PATH.
+
+.. _ebics-setup:
+
+Setting up the EBICS subscriber
+===============================
+
+.. include:: ../frags/nexus-ebics-setup.rst
+
+Database setup
+==============
+
+The configuration file must include a connection string that
+tells Nexus how it should connect to the database. The default
+is:
+
+.. code-block:: ini
+
+ [nexus-postgres]
+ config = postgres:///nexus
+
+You must make sure that this database exists and is accessible to the user
+running Nexus before continuing. Then, the Nexus database schema must be
+created (or updated) to the current Nexus version using the following command:
+
+.. code-block:: console
+
+ $ libeufin-nexus-dbinit -c "$CONFIG_FILE"
+
+where ``$CONFIG_FILE`` is again the path to a configuration that contains at
+least the above ``[nexus-postgres]`` section.
+
+.. _sending-payments:
+
+Sending payments
+================
+
+Sending payments must follow a successful `EBICS subscriber setup
+<ebics-setup>`_, where the bank obtained the subscriber keys, and the
+subscriber accepted the bank keys. Furthermore, the database has to
+be set up. Right now, some other process must queue payments to be
+submitted to the database, so this section only discusses how such
+queued payments will be executed.
+
+The responsible subcommand for sending payments is ``ebics-submit``, and its
+configuration is a **superset** of core-config_. On top of that, it expects
+the database connection string and *optionally* a frequency at which it will
+check for submittable payments in the database.
+
+The frequency **may** be specified as
+
+.. code-block:: ini
+
+ [nexus-submit]
+ FREQUENCY = 5m
+
+The supported time units are ``s`` (seconds), ``m`` (minutes), ``h`` (hours).
+
+
+For testing
+-----------
+
+The ``ebics-submit`` subcommand is **not** suitable to send arbitrary
+payments, but rather to submit initiated payments that are already queued for
+submission in the Nexus database.
+
+Such queued payments may originate from bounces of incoming payments with a
+subject that would be invalid for a Taler withdrawal, or from a Taler exchange
+that needs to send a payment to a merchant.
+
+For testing purposes it is possible to manually initiate a payment using the
+``initiate-payment`` subcommand.
+The following invocation pays 1 CHF to the CH987654321 with an "Hello, Nexus!"
+subject:
+
+.. code-block:: console
+
+ $ libeufin-nexus initiate-payment -c "$CONFIG_FILE" --subject "Hello, Nexus!" "payto://iban/CH987654321?receiver-name=Name&amount=CHF:1"
+
+``$CONFIG_FILE`` is the path to Nexus' configuration file and it does not need
+the FREQUENCY value. If the previous command worked, now the database should
+contain a new row in the ``initiated_outgoing_transactions`` table, with an
+``unsubmitted`` submission state.
+
+The following command would now pick such an unsubmitted initiated payment and
+send it to the bank.
+
+
+.. code-block:: console
+
+ $ libeufin-nexus ebics-submit -c "$CONFIG_FILE" --transient
+
+The ``--transient`` flag instructs the software to perform only one pass on
+the database, submit what is submittable, and return.
+
+The ``--debug-ebics $SAVEDIR`` flag will cause the files to be stored in
+``$SAVEDIR/$YYYY-MM-DD/submit`` where ``$YYYY-MM-DD`` represents the
+date when the upload took place. This is mostly useful for debugging.
+
+For production
+--------------
+
+The ``ebics-submit`` subcommand can run in fixed frequency, or transient mode.
+
+The fixed frequency mode causes the command to check the database every time the
+frequency period expires. To activate this mode, and -- for example -- set a frequency
+of five minutes, set the configuration value ``FREQUENCY`` to ``5m``. Assuming that
+``FREQUENCY`` is set as described above, the following invocation would
+make ``ebics-submit`` check the database every five minutes, and submit any initiated
+payment according to their submission state.
+
+.. code-block:: console
+
+ $ libeufin-nexus ebics-submit -c "$CONFIG_FILE"
+
+Transient mode causes ``ebics-submit`` to check the database only once, submit any
+initiated payment according to their submission state, and return.
+
+.. code-block:: console
+
+ $ libeufin-nexus ebics-submit -c "$CONFIG_FILE"
+
+
+.. _receive-transaction-data:
+
+Downloading payment records
+===========================
+
+Downloading payments must follow a successful `EBICS subscriber setup
+<ebics-setup>`_, where the bank obtained the subscriber keys, and the
+subscriber accepted the bank keys. Furthermore, the database has to
+be set up.
+
+The responsible subcommand for sending payments is ``ebics-fetch``, and its
+configuration is a **superset** of core-config_. On top of that, it expects
+the database connection string and *optionally* a frequency at which it will
+downloads any new EBICS files and ingest them in the database.
+
+The frequency **may** be specified as
+
+.. code-block:: ini
+
+ [nexus-fetch]
+ FREQUENCY = 5m
+
+The supported time units are ``s`` (seconds), ``m`` (minutes), ``h`` (hours).
+
+Assuming that ``$CONFIG_FILE`` contains all required options, the following
+command would download any unseen EBICS files:
+
+.. code-block:: console
+
+ $ libeufin-nexus ebics-fetch -c "$CONFIG_FILE" --transient
+
+The ``ebics-fetch`` subcommand will always cause libeufin-nexus to download
+then parse EBICS files and ingest their content statements into its local
+database.
+
+The files type can be given as an argument to select what will be fetched. If no argument is given, all supported files are fetched. The following files are supported:
+
+* ``acknowledgement``: EBICS acknowledgement, retrieves the status of EBICS orders.
+* ``status``: Payment status, retrieves status of pending debits.
+* ``notification``: Debit & credit notifications, retrieves the history of confirmed debits and credits.
+
+The ``--transient`` flag makes the command download and import EBICS files only
+once and return immediately afterwards. Without the flag, Nexus
+will download at the frequency specified in the configuration.
+
+The ``--debug-ebics $SAVEDIR`` flag will cause the files to be stored in
+``$SAVEDIR/$YYYY-MM-DD/fetch`` where ``$YYYY-MM-DD`` represents the
+date when the download took place. This is mostly useful for debugging.
+
+
+For Testing
+-----------
+
+If the bank account history has transactions that are useful for testing, it is
+possible to re-download them via the ``--pinned-start`` argument.
+
+The following command redownloads transactions *from* the pinned start until
+the present:
+
+.. code-block:: console
+
+ $ libeufin-nexus ebics-fetch -c "$CONFIG_FILE" --pinned-start 2023-11-01
+
+.. note::
+
+ If the Nexus database already contains the bank account history, you might need
+ to **reset** the database in order to have the re-downloaded transactions be
+ properly ingested. Be careful when resetting the database: resetting the wrong
+ database might cause DATA LOSS!
diff --git a/libeufin/nexus-tutorial.rst b/libeufin/nexus-tutorial.rst
deleted file mode 100644
index 51e0cd28..00000000
--- a/libeufin/nexus-tutorial.rst
+++ /dev/null
@@ -1,631 +0,0 @@
-.. target audience: operator, developer
-
-LibEuFin How-To
-###############
-
-.. contents:: Table of Contents
-
-The LibEuFin Nexus is a Web service that provides a JSON abstraction layer to
-access bank accounts. It does **not** itself offer banking services, but is a
-translator between JSON requests and other banking protocols (such as EBICS),
-that are offered by banks.
-
-This document explains how to set up Nexus to access a bank account
-via the EBICS protocol.
-
-In order to follow all the steps below, the reader should either
-have access to a bank account with EBICS support or follow the
-steps in :ref:`Configuring the Sandbox <configuring-the-sandbox>`.
-
-
-Installing LibEuFin
-===================
-
-Installation on Debian
-----------------------
-
-.. include:: ../frags/installing-debian.rst
-
-To install LibEuFin, you can now simply run:
-
-.. code-block:: console
-
- # apt install libeufin
-
-Administration via SystemD
---------------------------
-
-After the Debian installation, the installed unit files
-should be listed by the following command:
-
-.. code-block:: console
-
- # systemctl list-unit-files | egrep '(nexus|sandbox)'
-
-Both ``nexus.service`` and ``sandbox.service`` should appear.
-
-At this point, the services can be started on boot:
-
-.. code-block:: console
-
- # systemctl enable libeufin-nexus # use 'disable' to rollback
- # systemctl enable libeufin-sandbox # only if you want the sandbox
-
-Or just manually:
-
-.. code-block:: console
-
- # systemctl start libeufin-nexus # use 'stop' to terminate.
- # systemctl start libeufin-sandbox # only if you want the sandbox
-
-The following command should inform the user about the status
-of the running / terminated service:
-
-.. code-block:: console
-
- # systemctl status libeufin-nexus
-
-For more diagnostics, use:
-
-.. code-block:: console
-
- # journalctl -u libeufin-nexus
-
-Run-time dependencies
----------------------
-
-LibEuFin has the following run-time dependencies:
-
-* OpenJDK 11
-* Python 3.8
-* python3-click (can be installed via ``pip3 install click``)
-* python3-requests (can be installed via ``pip3 install requests``)
-
-These dependencies only need to be installed manually when building from source
-or using the prebuilt binaries.
-
-Downloading prebuilt binaries
------------------------------
-
-Pre-built packages can be obtained from the `taler.net website
-<https://taler.net/files/libeufin>`__.
-
-Unpack the ``libeufin-$version.zip`` file to
-your desired location (typically ``/opt`` or ``~/opt``) and make sure that your ``PATH``
-environment variable contains the ``bin/`` directory of the unpacked archive.
-
-Building from source
---------------------
-
-Nexus belongs to the LibEuFin project, and can be downloaded via Git:
-
-.. code-block:: console
-
- $ git clone git://git.taler.net/libeufin
-
-Note that Kotlin and Gradle should already work on the host system.
-
-Navigate into the *libeufin* local repository, and from top-level run:
-
-.. code-block:: console
-
- $ ./bootstrap
- $ ./configure --prefix=$PREFIX
- $ make install
-
-Verifying your installation
----------------------------
-
-In case of success, the three following commands should be found:
-
-.. code-block:: console
-
- $ which libeufin-nexus
- $ which libeufin-sandbox
- $ which libeufin-cli
-
-
-.. _configuring-the-sandbox:
-
-Configuring the Sandbox (Optional)
-==================================
-
-If you don't have access to a real bank account with an EBICS API, you can set
-up the sandbox. The sandbox is a simplistic and incomplete implementation of a
-core banking system with EBICS access to bank accounts.
-
-The sandbox relies on a database, which you must specify using a JDBC
-connection URI with the ``LIBEUFIN_SANDBOX_DB_CONNECTION`` environment
-variable, before invoking any commands.
-If this variable is not set, ``libeufin-sandbox`` complains and exits:
-
-.. code-block:: console
-
- $ libeufin-sandbox serve
- DB connection string not found/valid in the env variable LIBEUFIN_SANDBOX_DB_CONNECTION.
- The following two examples are valid connection strings:
- jdbc:sqlite:/tmp/libeufindb.sqlite3
- jdbc:postgresql://localhost:5432/libeufindb?user=Foo&password=secret
-
-Only *SQLite* and *PostgreSQL (via TCP)* are supported right now.
-
-For the following commands, the sandbox service must be running.
-The sandbox service is started with the following command:
-
-.. code-block:: console
-
- $ export LIBEUFIN_SANDBOX_DB_CONNECTION=jdbc:sqlite:/tmp/libeufintestdb
- $ libeufin-sandbox serve --port 5016
-
-To reset the state of the sandbox, delete the database.
-
-For invocations of the LibEuFin command-line interface tool (``libeufin-cli``),
-the following environment variable must be set to the URL of the sandbox
-service:
-
-.. code-block:: console
-
- $ export LIBEUFIN_SANDBOX_URL=http://localhost:5016/
-
-Verify that the sandbox is running:
-
-.. code-block:: console
-
- $ libeufin-cli sandbox check
- {
- "name" : "libeufin-sandbox",
- "version" : "0.0.0-dev.0"
- }
-
-Now an EBICS host can be created:
-
-.. code-block:: console
-
- $ libeufin-cli sandbox ebicshost create --host-id testhost
-
-Note that most ``libeufin-cli`` subcommands will ask for input interactively if
-the respective value is not specified on the command line.
-
-Next, create an EBICS subscriber (identified by the partner ID and user ID) for the host:
-
-.. code-block:: console
-
- $ libeufin-cli sandbox ebicssubscriber create \
- --host-id testhost --partner-id partner01 --user-id user01
-
-Create a bank account for the subscriber and add a sample transaction:
-
-.. code-block:: console
-
- $ libeufin-cli sandbox ebicsbankaccount create \
- --currency EUR \
- --iban DE18500105172929531888 \
- --bic INGDDEFFXXX \
- --person-name "Jane Normal" \
- --account-name "testacct01" \
- --ebics-host-id testhost \
- --ebics-user-id user01 \
- --ebics-partner-id partner01
-
-The account name ``testacct01`` is the unique identifier of the account within
-the sandbox. The EBICS parameters identify the subscriber that should have
-access to the bank account via EBICS.
-
-To populate the account with some test transactions, run the following command
-(note that we use the ``bankaccount`` subcommand, because there is no need to rely
-on EBICS):
-
-.. code-block:: console
-
- $ libeufin-cli sandbox bankaccount generate-transactions testacct01
-
-.. code-block:: console
-
- $ libeufin-cli sandbox bankaccount simulate-incoming-transaction testacct01 \
- --debtor-iban DE06500105174526623718 \
- --debtor-bic INGDDEFFXXX \
- --debtor-name "Joe Foo" \
- --subject "Hello World" \
- --amount 10.50
-
-Payments to a sandbox bank account can be listed as follows:
-
-.. code-block:: console
-
- $ libeufin-cli sandbox bankaccount transactions testacct01
-
-.. note::
-
- The sandbox is intended as a testing tool and thus not stable.
-
-For more information on the available commands, use the built-in ``--help`` flag.
-The full functionality of the sandbox is available via
-the :ref:`Sandbox API <sandbox-api>`.
-
-
-Connect Nexus with an EBICS account
-===================================
-
-Nexus relies on a database, which you must specify using a JDBC
-connection URI with the ``LIBEUFIN_NEXUS_DB_CONNECTION`` environment
-variable, before invoking any commands.
-(If this variable is not set, ``libeufin-nexus`` complains and exits.)
-
-Only *SQLite* (e.g. ``jdbc:sqlite:/tmp/libeufintestdb``) and *PostgreSQL (via TCP)*
-(e.g. ``jdbc:postgresql://localhost:$port/libeufintestdb?user=$username&password=$password``)
-are supported right now.
-
-Use the following command to run the nexus service:
-
-.. code-block:: console
-
- $ export LIBEUFIN_NEXUS_DB_CONNECTION=jdbc:postgresql://localhost:5433/libeufindb?user=foo&password=secret
- $ libeufin-nexus serve --port 5017
-
-This assumes that the PostgreSQL service with a database
-called ``libeufindb`` listens on port 5433
-for requests from the nexus service.
-The nexus service itself listens on port 5017.
-Note that you must have the ``LIBEUFIN_NEXUS_DB_CONNECTION``
-environment variable set for most uses of the libeufin-nexus
-command.
-
-At this point a superuser account needs to be created:
-
-.. code-block:: console
-
- $ libeufin-nexus superuser foo --password secret
-
-If you omit ``--password secret``, you will interactively be asked for a password.
-For simplicity, a superuser can as well act as a normal user, but an API
-to create less privileged users is offered.
-
-.. note::
-
- User and permissions management in LibEuFin is still under development.
- In particular, permissions for non-superusers are very limited at the moment.
-
-The command line interface needs the following three values
-to be defined in the environment: ``LIBEUFIN_NEXUS_URL``, ``LIBEUFIN_NEXUS_USERNAME``,
-and ``LIBEUFIN_NEXUS_PASSWORD``. In this example, ``LIBEUFIN_NEXUS_USERNAME`` should be
-set to ``foo``, and ``LIBEUFIN_NEXUS_PASSWORD`` to the value given for its password
-in the previous step (with the ``libeufin-nexus superuser`` command). The
-``LIBEUFIN_NEXUS_URL`` could be given as ``http://localhost:5017/``.
-
-Next, we create a EBICS *bank connection* that nexus can use to communicate with the bank.
-
-.. note::
-
- For the sandbox setup in this guide, the ``EBICS_BASE_URL``
- should be ``http://localhost:5016/ebicsweb``.
-
-.. code-block:: console
-
- $ libeufin-cli \
- connections \
- new-ebics-connection \
- --ebics-url $EBICS_BASE_URL \
- --host-id $EBICS_HOST_ID \
- --partner-id $EBICS_PARTNER_ID \
- --ebics-user-id $EBICS_USER_ID \
- $CONNECTION_NAME
-
-If this step executes correctly, Nexus will have created all the cryptographic
-material that is needed on the client side; in this EBICS example, it created
-the signature and identification keys. It is therefore advisable to *make
-a backup copy* of such keys.
-
-.. code-block:: console
-
- $ libeufin-cli \
- connections \
- export-backup \
- --passphrase $SECRET \
- --output-file $BACKUP_FILE \
- $CONNECTION_NAME
-
-At this point, Nexus needs to both communicate its keys to the bank, and
-download the bank's keys. This syncronization happens through the INI, HIA, and
-finally, HPB message types.
-
-After the electronic synchronization, the subscriber must confirm their keys
-by sending a physical mail to the bank. The following command helps generating
-such letter:
-
-.. code-block:: console
-
- $ libeufin-cli connections get-key-letter $CONNECTION_NAME out.pdf
-
-.. note::
-
- When using the LibEuFin sandbox, subscribers are automatically
- activated after keys are received electronically.
-
-.. code-block:: console
-
- $ libeufin-cli \
- connections \
- connect \
- $CONNECTION_NAME
-
-Once the connection is synchronized, Nexus needs to import locally the data
-corresponding to the bank accounts offered by the bank connection just made.
-The command below downloads the list of the bank accounts offered by ``$CONNECTION_NAME``.
-
-.. code-block:: console
-
- $ libeufin-cli \
- connections \
- download-bank-accounts \
- $CONNECTION_NAME
-
-It is now possible to list the accounts offered by the connection.
-
-.. code-block:: console
-
- $ libeufin-cli \
- connections \
- list-offered-bank-accounts \
- $CONNECTION_NAME
-
-.. note::
-
- The ``nexusBankAccountId`` field should at this step be ``null``,
- as we have not yet imported the bank account and thus the account
- does not yet have a local name.
-
-Nexus now needs an explicit import of the accounts it should manage. This
-step is needed to let the user pick a custom name for such accounts.
-
-.. code-block:: console
-
- $ libeufin-cli \
- connections \
- import-bank-account \
- --offered-account-id testacct01 \
- --nexus-bank-account-id $LOCAL_ACCOUNT_NAME \
- $CONNECTION_NAME
-
-Once a Nexus user imported a bank account (``$LOCAL_ACCOUNT_NAME``)
-under a certain connection (``$CONNECTION_NAME``), it is possible
-to accomplish the usual operations for any bank account: asking for the
-list of transactions, and making a payment.
-
-Request history of transactions
-===============================
-
-The LibEuFin nexus keeps a local copy of the bank account's transaction
-history. Before querying transactions locally, it is necessary
-to request transactions for the bank account via the bank connection.
-
-This command asks Nexus to download the latest transaction reports/statements
-through the bank connection:
-
-.. code-block:: console
-
- $ libeufin-cli accounts fetch-transactions $LOCAL_ACCOUNT_NAME
-
-.. note::
-
- By default, the latest available transactions are fetched. It is also
- possible to specify a custom date range (or even all available transactions)
- and the type of transactions to fetch (inter-day statements or intra-day
- reports).
-
-Once Nexus has stored all the information in the database, the
-client can ask to actually see the transactions:
-
-.. code-block:: console
-
- $ libeufin-cli accounts transactions $LOCAL_ACCOUNT_NAME
-
-Make a payment
-==============
-
-Payments pass through two phases: preparation and submission. The preparation
-phase assigns the payment initiation a unique ID, which prevents accidental
-double submissions of payments in case of network failures or other
-disruptions.
-
-
-The following command prepares a payment:
-
-.. code-block:: console
-
- $ libeufin-cli accounts prepare-payment \
- --creditor-iban=$IBAN_TO_SEND_MONEY_TO \
- --creditor-bic=$BIC_TO_SEND_MONEY_TO \
- --creditor-name=$CREDITOR_NAME \
- --payment-amount=$AMOUNT \
- --payment-subject=$SUBJECT \
- $LOCAL_ACCOUNT_NAME
-
-Note: the ``$AMOUNT`` value needs the format ``CURRENCY:X.Y``; for example
-``EUR:10``, or ``EUR:1.01``.
-
-The previous command should return a value (``$UUID``) that uniquely
-identifies the prepared payment in the Nexus system. That is needed
-in the next step, to **send the payment instructions to the bank**:
-
-.. code-block:: console
-
- $ libeufin-cli accounts submit-payment \
- --payment-uuid $UUID \
- $LOCAL_ACCOUNT_NAME
-
-Automatic scheduling
-====================
-
-With an EBICS bank connection, the LibEuFin nexus needs to regularly query for
-new transactions and (re-)submit prepared payments.
-
-It is possible to schedule these tasks via an external task scheduler such as
-cron(8). However, the nexus also has an internal task scheduling mechanism for
-accounts.
-
-
-The following three commands create a schedule for submitting payments hourly,
-fetching transactions (intra-day reports) every 5 minutes, and (inter-day statements)
-once at 11pm every day :
-
-.. code-block:: console
-
- $ libeufin-cli accounts task-schedule myacct \
- --task-type="submit" \
- --task-name='submit-payments-hourly' \
- --task-cronspec='0 0 *'
-
- $ libeufin-cli accounts task-schedule myacct \
- --task-type="fetch" \
- --task-name='fetch-5min' \
- --task-cronspec='0 */5 *' \
- --task-param-level=report \
- --task-param-range-type=latest
-
- $ libeufin-cli accounts task-schedule myacct \
- --task-type="fetch" \
- --task-name='fetch-daily' \
- --task-cronspec='0 0 23' \
- --task-param-level=statement \
- --task-param-range-type=latest
-
-The cronspec has the following format, which is slightly non-standard due to
-the ``SECONDS`` field
-
-.. code-block:: none
-
- SECONDS MINUTES HOURS DAY-OF-MONTH[optional] MONTH[optional] DAY-OF-WEEK[optional]
-
-
-Restore the backup
-==================
-
-The following command restores all the details associated with
-one bank connection subscription. For EBICS, this means that the
-INI and HIA secret keys will be restored for the requesting user.
-
-.. code-block:: console
-
- $ libeufin-cli connections \
- restore-backup \
- --passphrase=$SECRET \
- --backup-file=$BACKUP_FILE \
- $CONNECTION_NAME
-
-..
- FIXME:
- On a bad password given, Nexus responds
- "bad backup given" instead of "authentication failed".
-
-
-Creating a Taler facade
-=======================
-
-Facades are additional abstraction layers that can serve
-specific purposes. For example, one application might need
-a filtered version of the transaction history, or it might
-want to refuse payments that do not conform to certain rules.
-
-At this moment, only the *Taler facade type* is implemented
-in the Nexus, and the command below instantiates one under a
-existing bank account / connection pair. You can freely
-assign an identifier for the ``$FACADE_NAME`` below:
-
-.. code-block:: console
-
- $ libeufin-cli facades new-taler-wire-gateway-facade \
- --currency EUR \
- --facade-name $FACADE_NAME \
- $CONNECTION_NAME \
- $LOCAL_ACCOUNT_NAME
-
-At this point, the additional *taler-wire-gateway* (FIXME: link
-here to API here) API becomes offered by the Nexus. The purpose
-is to let a Taler exchange rely on Nexus to manage its bank account.
-
-The base URL of the facade that can be used by the Taler exchange
-as the Taler Wire Gateway base URL located when listing the facades:
-
-.. code-block:: console
-
- $ libeufin-cli facades list
-
-Creating a Anastasis facade
-===========================
-
-The following command creates a Anastasis facade. At this point, *only*
-the superuser is able to create facades; please set the environment variables
-``LIBEUFIN_NEXUS_USERNAME`` and ``LIBEUFIN_NEXUS_PASSWORD`` accordingly.
-
-.. code-block:: console
-
- $ libeufin-cli facades new-anastasis-facade \
- --currency EUR \
- --facade-name $FACADE_NAME \
- $CONNECTION_NAME \
- $LOCAL_ACCOUNT_NAME
-
-If the previous command succeeded, it is possible to see the
-facade's base URL with:
-
-.. code-block:: console
-
- $ libeufin-cli facades list
-
-At this point, to allow a non superuser to use the facade, a history
-permission needs to be set:
-
-.. code-block:: console
-
- $ libeufin-cli permissions grant \
- user $USERNAME \
- facade $FACADENAME \
- facade.anastasis.history
-
-.. note::
-
- There is no need to set/unset a transfer permission on the facade
- since this one does not offer any endpoint to issue wire transfers.
-
-Managing Permissions and Users
-==============================
-
-This guide has so far assumed that a superuser is accessing the LibEuFin Nexus.
-However, it is advisable that the Nexus is accessed with users that only have a
-minimal set of permissions.
-
-The Nexus currently only has support for giving non-superusers access to Taler
-wire gateway facades.
-
-To create a new user, use the ``users`` subcommand of the CLI:
-
-.. code-block:: console
-
- $ libeufin-cli users list
- # [ ... shows available users ... ]
-
- $ libeufin-cli users create $USERNAME
- # [ ... will prompt for password ... ]
-
-Permissions are managed with the ``permissions`` subcommand.
-The following commands grant permissions to view the transaction history
-and create payment initiations with a Taler wire gateway facade:
-
-
-.. code-block:: console
-
- $ libeufin-cli permissions grant \
- user $USERNAME \
- facade $FACADENAME \
- facade.talerWireGateway.history
-
- $ libeufin-cli permissions grant \
- user $USERNAME \
- facade $FACADENAME \
- facade.talerWireGateway.transfer
-
-The list of all granted permissions can be reviewed:
-
-.. code-block:: console
-
- $ libeufin-cli permissions list
diff --git a/libeufin/no-accounts.png b/libeufin/no-accounts.png
new file mode 100644
index 00000000..a180f7a1
--- /dev/null
+++ b/libeufin/no-accounts.png
Binary files differ
diff --git a/libeufin/regional-automated-manual.rst b/libeufin/regional-automated-manual.rst
new file mode 100644
index 00000000..f416d1b9
--- /dev/null
+++ b/libeufin/regional-automated-manual.rst
@@ -0,0 +1,261 @@
+..
+ This file is part of GNU TALER.
+ Copyright (C) 2014-2024 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Florian Dold
+ @author Marcello Stanisci
+ @author Christian Grothoff
+
+
+.. target audience: operator
+
+Regional Currency Automated Setup Manual
+########################################
+
+This manual describes how to setup a regional currency using a script that largely automates the process. If you want to do a custom setup you can follow the :doc:`custom setup manual<regional-custom-manual>`.
+
+
+.. contents:: Table of Contents
+ :local:
+
+.. include:: ../frags/regional-manual-architecture.rst
+
+Guided Automated Setup
+======================
+
+Prerequisites
++++++++++++++
+
+For this manual, we assume that the system is deployed on a contemporary
+Debian GNU/Linux Bookworm or Ubuntu Mantic system using the binary packages provided.
+Furthermore, you should run the process on a system with one or more globally
+reachable IP address(es) *and* with various DNS names already pointing to
+these IPs.
+
+Preparing the required subdomain names
+++++++++++++++++++++++++++++++++++++++
+
+The GNU Taler program needs to have three subdomains pointing to your server IP address, in order to let NGINX to accommodate each component.
+These are "bank", "exchange" and "backend", this said, you need to have a registered top level domain name,
+where you can create type (A) entries, as subdomains pointing to your own server public IP address.
+A very good advice when creating these subdomains, and if your domain panel lets you specify the TTL (time to live) figure, is
+to specify a very low value (such as 300), so in case of future changes, its value (the IP address), will be propagated quickly.
+
+Once you have added the three required subdomains in your domain control panel, you have to make sure as well, these subdomains have
+propagated over the Internet correctly, and they are currently publicly available.
+
+You can check this from your terminal very easily with the "ping" command, as this:
+
+.. code-block:: console
+
+ $ ping -c1 bank.$DOMAIN_NAME
+ $ ping -c1 exchange.$DOMAIN_NAME
+ $ ping -c1 backend.$DOMAIN_NAME
+
+You can also use `this tool <https://toolbox.googleapps.com/apps/dig/>`_ for the same purpose, and to check the propagation status.
+
+.. warning::
+ Take into account some hosting providers providing virtualized servers (VPS or VDS) can enable by default the firewall program "UFW", blocking by default the port number 443. So you have to either disable this firewall program, or open to this 443 port number to allow https.
+
+Now you are ready to go with the next step.
+
+Obtaining the Scripts
++++++++++++++++++++++
+
+First, download the deployment scripts via Git:
+
+.. code-block:: console
+
+ # apt update && apt install git
+ $ git clone git://git.taler.net/deployment
+
+Running the Guided Configuration
+++++++++++++++++++++++++++++++++
+
+Navigate into the *regional-currency/* directory and run *main.sh* as **root**:
+
+.. code-block:: console
+
+ $ cd deployment/regional-currency/
+ # ./main.sh
+
+The script will start by installing the required packages and then asking you fundamental questions about the desired setup, in particular:
+
+#. Wether to encrypt, when stored on disk, sensible configurations such as the admin password.
+#. The name of the regional currency. It must have 3 to 11 letters.
+#. Whether to setup the regional currency to be backed by a fiat currency. You'll need a bank account at a fiat currency bank offering an online banking protocol supported by LibEuFin Nexus. If you answer ``y``, you will also need to provide the following information:
+
+ #. The ISO code of the fiat currency. Use 'CHF' or 'EUR'.
+ #. The IBAN of the fiat bank account.
+ #. The BIC of the fiat bank account.
+ #. The legal name of the fiat bank account.
+
+#. The name of the regional currency bank. It will be shown to business users when they interact with the system.
+#. The DNS domain name of your setup (i.e: domain.tld). The installer will create by itself all the needed subdomains for your domain name, as (``bank.$DOMAIN_NAME``, ``exchange.$DOMAIN_NAME`` and ``backend.$DOMAIN_NAME``). But, these subdomain names as explained before, must have been added beforehand to your DNS domain control panel, and they must be pointing to the IP address of the server on which you are running the installation (before you execute the installer).
+#. Whether to use TLS or not. You should answer ``y`` in most cases.
+#. Whether to setup SMS two-factor authentication using `Telesign <https://www.telesign.com>`_, multi-factor authentication is strongly recommended, especially when regional currency can be converted to fiat currency. This requires `a Customer ID and an API Key <https://developer.telesign.com/enterprise/docs/authentication#basic-authentication>`_. You should answer ``y`` in most cases.
+#. The admin password for the bank. Be absolutely sure to enter a very, very long and high-entropy password, preferably using the autogenerated one.
+#. Whether to generate terms of service (ToS) for the exchange from default templates.
+#. Whether to generate a privacy policy for the exchange from default templates.
+
+The information you entered as well as the generated bank admin password will
+be stored in a file called ``config/user.conf``. If you run the script in
+the future again (for example, to upgrade the installation), you will not be asked
+these questions a second time.
+
+After answering all of the questions, the actual installation will start. The
+scripts will download and configure various packages, which may take some time.
+Grab a coffee.
+
+.. note::
+
+ At this point, the setup is NOT connected to any fiat bank account! The next
+ steps must always be done manually!
+
+Running the script again from scratch
++++++++++++++++++++++++++++++++++++++
+
+If for some reason your installation doesn't work because you have answered erroneously
+some of the interactive questions, or you just want to reset the current installation and to re-deploy
+the script again for having its latest changes, you will have to proceed as follows:
+
+In brief, you need to wipe completely the "content" of the file config/user.conf, this doesn't mean
+to remove the file itself, but only its content. Even though you can do this manually by editing the file manually
+with your preferred text editor, you can also do this in one single command.
+
+.. code-block:: console
+
+ # rm config/user.conf
+
+.. note::
+
+ In future versions of the program when executed for the second time, the program itself will
+ show an option to offer wiping the content of this config/user.conf file, automatically.
+
+Multi-factor authentication
++++++++++++++++++++++++++++
+
+The script allows you to configure multi-factor authentication via SMS using Telesign as a provider. You can also configure multi-factor authentication via email or use providers other than Telesign for SMS. You will need to configure these channels manually as described in :ref:`multi-factor authentication <libeufin-mfa>`.
+
+If you choose not to back your regional currency with a fiat currency, you can stop here.
+
+Web-based Configuration
++++++++++++++++++++++++
+
+By default, the regional currency conversion rates are 1:1. You can change the conversion rates and the ``admin`` debt limit via the bank's web interface as the ``admin`` user.
+
+Connecting to a Fiat Bank: the EBICS setup
+++++++++++++++++++++++++++++++++++++++++++
+
+To complete the conversion setup, you have to set up an EBICS subscriber using the fiat bank account you specified during the automated setup.
+
+When you sign up for an EBICS-enabled bank account, the bank will provide you
+with various credentials. Those must be provided in the
+``/etc/libeufin/libeufin-nexus.conf`` configuration file.
+
+.. note::
+ As legacy transactions in that bank account would likely confuse the system, it is advisable to use a fresh bank account with an empty transaction history.
+ If this is not possible, use the ``IGNORE_TRANSACTIONS_BEFORE`` configuration to ignore old transactions.
+
+The following snippet shows the mandatory configuration values:
+
+.. _core-config:
+
+.. code-block:: ini
+
+ [nexus-ebics]
+ # Bank
+ HOST_BASE_URL = https://ebics.postfinance.ch/ebics/ebics.aspx
+ BANK_DIALECT = postfinance
+
+ # EBICS IDs
+ HOST_ID = PFEBICS
+ USER_ID = PFC00563
+ PARTNER_ID = PFC00563
+
+.. warning::
+ This combination of HOST_ID, USER_ID and PARTNER_ID must never be used by another instance of libeufin-nexus or by other EBICS clients, otherwise data will be lost.
+
+Reuse existing client keys
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If you have client keys from a previous EBICS setup you can copy the JSON file to ``/var/lib/libeufin-nexus/client-ebics-keys.json``.
+
+Make sure this file is accessible to the user running ``libeufin-nexus``, you should run:
+
+.. code-block:: console
+
+ $ chown libeufin-nexus:libeufin-nexus /var/lib/libeufin-nexus/client-ebics-keys.json
+
+Create new client keys
+^^^^^^^^^^^^^^^^^^^^^^
+
+Run the following command to start the EBICS setup process:
+
+.. code-block:: console
+
+ $ sudo -u libeufin-nexus libeufin-nexus ebics-setup
+
+If the previous command failed when running EBICS INI with an error code of
+``EBICS_INVALID_USER_OR_USER_STATE``, you need to confirm your keys to your bank to
+activate your account.
+
+To that end, the previous run should have left a PDF document that you can
+print, sign and send to the bank. Look for the message that looks like ``PDF
+file with keys created at '/tmp/libeufin-nexus-keys-$TIMESTAMP.pdf'``.
+
+Once the bank has received and processed this document you can continue.
+
+Get bank keys
+^^^^^^^^^^^^^
+
+Run the following command to finish the EBICS setup process:
+
+.. code-block:: console
+
+ $ sudo -u libeufin-nexus libeufin-nexus ebics-setup
+
+The EBICS setup is finished once the bank keys have been accepted.
+
+
+Configuring the Exchange for Conversion
++++++++++++++++++++++++++++++++++++++++
+
+In our automated setup the second account is automatically set up correctly
+without fees or special restrictions. However, various additional
+*restrictions* and *options* could be configured. Details are explained in
+the :ref:`regional conversion setup <regional-conversion-setup>` section for the
+manual setup and in the the manpage of ``taler-exchange-offline``.
+
+
+.. include:: ../frags/regional-system-on.rst
+.. include:: ../frags/deploying-tos.rst
+.. include:: ../frags/regional-manual-use.rst
+
+
+Installing Updates
+++++++++++++++++++
+
+The standard procedure for installing updates is to:
+
+* First, make a backup (!)
+* Stop Taler services
+* Install new version
+* Upgrade databases
+* Start Taler services
+
+The "upgrade.sh" script in the "regional-currency/" folder of "deployment.git"
+shows how to do the above steps *except* for the backup. For the backup, all
+critical bits of data will be in the Postgresql databases. Thus, we recommend
+following the database manual on making backups.
diff --git a/libeufin/regional-custom-manual.rst b/libeufin/regional-custom-manual.rst
new file mode 100644
index 00000000..7da39c96
--- /dev/null
+++ b/libeufin/regional-custom-manual.rst
@@ -0,0 +1,181 @@
+..
+ This file is part of GNU TALER.
+ Copyright (C) 2014-2024 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Florian Dold
+ @author Marcello Stanisci
+ @author Christian Grothoff
+
+
+.. target audience: operator
+
+Regional Currency Custom Setup Manual
+#####################################
+
+This manual describes how to setup a regional currency manually. If you want a guided setup you can follow the :doc:`automated setup manual<regional-automated-manual>`.
+
+.. contents:: Table of Contents
+ :local:
+
+.. include:: ../frags/regional-manual-architecture.rst
+
+Custom Manual Setup
+===================
+
+You first need to setup the :ref:`libeufin-bank<libeufin-bank>` and integrate it with a Taler exchange.
+
+If you don't want your regional currency to be backed by a fiat currency, you can stop here.
+
+Enabling Currency Conversion
+++++++++++++++++++++++++++++
+
+You need to setup the :ref:`libeufin-nexus<libeufin-nexus>` using a bank account at a bank dealing in fiat currency that
+offers an online banking protocol supported by LibEuFin Nexus.
+
+Next, you have to enable conversion and should ensure that at least one TAN
+channel for :ref:`multi-factor authentication <libeufin-mfa>` is configured.
+
+The following snippet shows how to enable conversion in ``libeufin-bank`` configuration:
+
+.. code-block:: ini
+
+ [libeufin-bank]
+ ALLOW_CONVERSION = YES
+ FIAT_CURRENCY = EUR
+
+Make sure to (re)start the libeufin-bank after changing
+these configuration options:
+
+.. code-block:: console
+
+ # systemctl restart libeufin-bank
+
+
+Web-based Configuration
++++++++++++++++++++++++
+
+Now you have to set the conversion rates and the ``admin`` debt limit via the bank's web interface as the ``admin`` user.
+
+.. _regional-conversion-setup:
+
+Configuring the Exchange for Conversion
++++++++++++++++++++++++++++++++++++++++
+
+An exchange that supports currency conversion needs to advertise two bank
+accounts, one in the regional currency and a second in the fiat currency. The
+conversion logic ensures that wire transfers in either account are
+immediately reflected in the other account.
+
+This section explains how to enable currency conversion at the exchange,
+which is critical for wallets to know how to wire fiat currency to an
+exchange to obtain regional currency.
+
+You will need to use the ``taler-exchange-offline`` tool to inform the
+exchange about the **fiat** bank account that can be used for cash in
+operations and also specify the URL for currency conversion. Additionally,
+you may also configure restrictions on the bank accounts that may originate
+the funds, for example, to prevent international wire transfers that may expose
+you to additional compliance risks.
+
+Given the ``$IBAN`` of the fiat currency bank account and ``$NAME`` as
+the (URL-encoded) name of the exchange-account owner, the following
+``taler-exchange-offline`` invocation can be used to notify wallets about
+the possibility of currency conversion (cash in):
+
+.. code-block:: console
+
+ # source config/user.conf
+ # sudo -u taler-exchange-offline \
+ taler-exchange-offline \
+ wire-fee now iban "${CURRENCY}":0 "${CURRENCY}":0 \
+ enable-account \
+ "${CONVERSION_PAYTO}" \
+ conversion-url "${PROTO}://bank.$DOMAIN_NAME/conversion-info/" \
+ display-hint 10 "CHF" \
+ debit-restriction deny \
+ credit-restriction \
+ regex \
+ 'payto://iban/.*/CH.*?receiver-name=.*' \
+ 'Swiss only' \
+ '{"de":"nur Schweiz","fr":"Suisse uniquement"}' \
+ upload
+
+Here, the ``$CONVERSION_URL`` must be set to the base URL of the conversion
+endpoint of the bank, which should be
+``https://bank.$DOMAIN/conversion-info/`` in our setup.
+
+The above commands set up the exchange to perform conversion with a
+restriction to only accept credit transfers from Swiss bank accounts. You may
+want to configure such restrictions on the bank accounts that may originate
+funds to prevent international wire transfers that may expose you to
+additional compliance risks.
+
+You can leave out the "credit-restriction" if you want to allow international
+inbound wire transfers.
+
+The "debit-restriction" is largely mandatory as in this setup the
+``taler-exchange-transfer`` is only configured to deal with the regional
+currency bank. Crediting fiat bank accounts must thus be done via the
+cash-out functionality of the regional currency bank account.
+
+The "display-hint" gives priority (10) for the fiat cash-in account over the
+regional currency account in the withdraw dialog of the wallets and labels the
+account with "CHF".
+
+.. note::
+
+ The above command adds a **second** bank account to the exchange.
+ You (or the guided setup script) should have already enabled the
+ regional currency bank account (without any "conversion-url").
+
+.. include:: ../frags/regional-system-on.rst
+.. include:: ../frags/deploying-tos.rst
+.. include:: ../frags/regional-manual-use.rst
+
+
+Maintenance
++++++++++++
+
+The ``taler-exchange-offline`` commands given above set fees only for the
+current year (``now``). Thus, before January 1st of each year, you must to set
+up new fees for the new calendar year. In a regional currency setup, this
+typically requires up to three annual settings:
+
+.. code-block:: console
+
+ # YEAR=2025 # edit if necessary
+ # FIAT_CURRENCY=CHF # edit if necessary
+ # REGIO_CURRENCY=NETZBON # edit if necessary
+ # sudo -u taler-exchange-offline \
+ taler-exchange-offline \
+ wire-fee "$YEAR" \
+ iban "${FIAT_CURRENCY}":0 "${FIAT_CURRENCY}":0 \
+ wire-fee "$YEAR" \
+ x-taler-bank "${REGIO_CURRENCY}":0 "${REGIO_CURRENCY}":0 \
+ global-fee $YEAR \
+ "${REGIO_CURRENCY}:0" \
+ "${REGIO_CURRENCY}:0" \
+ "${REGIO_CURRENCY}:0" \
+ 4w 6y 4 \
+ upload
+
+If the fees are not all zero, simply change the respective place to specify
+a non-zero fee.
+
+.. note::
+
+ Additionally, the denomination signing keys will only have been
+ pre-generated for some time, depending on your ``LOOKAHEAD_SIGN``
+ configuration option. Thus, you may need to periodically run
+ the "taler-exchange-offline download sign upload" sequence as well!
diff --git a/libeufin/sepa.rst b/libeufin/sepa.rst
deleted file mode 100644
index 29baca00..00000000
--- a/libeufin/sepa.rst
+++ /dev/null
@@ -1,26 +0,0 @@
-.. target audience: core developer
-
-SEPA Payments
-#############
-
-This page collects reference materials and details for specifics of SEPA payments.
-
-SEPA Credit Transfer (SCT)
-==========================
-
-SCT is a "normal" bank transfer. Details (terminology, data definitions, flow diagrams) can be found in the EPC's
-`SCT rulebook <https://www.europeanpaymentscouncil.eu/document-library/rulebooks/sepa-credit-transfer-rulebook>`__.
-
-
-Reject vs Return vs Recall
---------------------------
-
-* A **rejected** payment is refused by the originator bank or the
- clearing and settlement layer.
-* A **returned** payment is refused by the beneficiary's bank via a
- counter-transaction over the settlement layer.
-* A payment is **recalled** when the originator's bank (potentially
- requested by the originator) wants to "undo" a SCT.
-
-SEPA currently does **not** directly support a mechanism for the **beneficiary** to return
-a payment.
diff --git a/libeufin/set-EBICS-keys.png b/libeufin/set-EBICS-keys.png
new file mode 100644
index 00000000..71ecfa86
--- /dev/null
+++ b/libeufin/set-EBICS-keys.png
Binary files differ
diff --git a/libeufin/set-IBAN.png b/libeufin/set-IBAN.png
new file mode 100644
index 00000000..277019e5
--- /dev/null
+++ b/libeufin/set-IBAN.png
Binary files differ
diff --git a/libeufin/set-ISO-2019-0.png b/libeufin/set-ISO-2019-0.png
new file mode 100644
index 00000000..34bfe8dc
--- /dev/null
+++ b/libeufin/set-ISO-2019-0.png
Binary files differ
diff --git a/libeufin/set-ISO-2019-1.png b/libeufin/set-ISO-2019-1.png
new file mode 100644
index 00000000..8f45922e
--- /dev/null
+++ b/libeufin/set-ISO-2019-1.png
Binary files differ
diff --git a/libeufin/set-english-and-register.png b/libeufin/set-english-and-register.png
new file mode 100644
index 00000000..5e88c1d7
--- /dev/null
+++ b/libeufin/set-english-and-register.png
Binary files differ
diff --git a/libeufin/setup-ebics-at-postfinance.rst b/libeufin/setup-ebics-at-postfinance.rst
new file mode 100644
index 00000000..161bc6d3
--- /dev/null
+++ b/libeufin/setup-ebics-at-postfinance.rst
@@ -0,0 +1,90 @@
+Setup EBICS at PostFinance test platform
+########################################
+
+In this tutorial, we will set up one EBICS 3 account at the PostFinance
+test platform, in order to test the ``postfinance`` dialect from ``libeufin-nexus``.
+
+The first requirement is to create one account `there <https://isotest.postfinance.ch>`_.
+It is advised to set the language as English, as this tutorial is meant
+for the international audience.
+
+Set the language in the drop-down menu and navigate to the registration
+section as it is shown below:
+
+.. image:: set-english-and-register.png
+
+Even if the above page doesn't welcome you in English, the two boxes in the
+screenshot will still hold their position, so please look for box #1 to
+set the language and for box #2 to get the page that offers to register.
+
+After a successful registration, an IBAN needs to be associated with
+the user just created. Likely after the first login, the following
+page should appear. Click then on box #2.
+
+.. note::
+
+ The navigation bar in the screenshot below is ubiquitous,
+ so click on box #1 if the depicted page did not show up automatically.
+
+.. image:: no-accounts.png
+
+If the following page appears, please obtain a checksum-valid but fictitious
+Swiss IBAN and enter it as indicated by box #1 and then save it (box #2).
+
+.. _my-iban:
+
+.. image:: set-IBAN.png
+
+If the bank responds with a successful message, the next step is to enable
+EBICS 3 and set the format of the ISO20022 documents.
+
+.. note::
+
+ There is no "use EBICS 3" setting since EBICS 3 is a "side effect"
+ of choosing one particular ISO format for banking records.
+
+To use EBICS 3, click the navigation bar item highlighted in the
+following screenshot.
+
+.. image:: set-ISO-2019-0.png
+
+The following page should appear, where the ISO format can be specified
+as it is depicted in the following screenshot.
+
+.. image:: set-ISO-2019-1.png
+
+After having saved the setting, proceed now to set the flavor
+of payment confirmations. This setting instructs the bank to define
+particular XML nodes when it releases the payment confirmations. Even
+if each document is ISO20022, this step is essential because ISO20022
+has many optional fields and client and bank must agree on which fields
+appear in the documents.
+
+Hover on box #1 and then click on box #2.
+
+.. image:: camt.054-style-0.png
+
+If the following page appears, please set everything as it is shown below:
+
+.. image:: camt.054-style-1.png
+
+.. _get-ebics-ids:
+
+The last step is to retrieve the user's EBICS identifiers, namely the
+EBICS user and partner IDs. Hover on box #1 and then click on box #2.
+
+.. image:: get-EBICS-IDs-0.png
+
+At the first access, the following page should appear. Simply create
+EBICS access and continue to the next step.
+
+.. image:: enable-EBICS.png
+
+After having obtained the following page, finally the EBICS identifiers
+are shown in box #1.
+
+.. image:: get-EBICS-IDs-1.png
+
+Finally, box #2 contains the bank keys fingerprints. These are
+important to check that the client, along the keying process, has obtained
+the right bank keys.
diff --git a/libeufin/transaction-identification.rst b/libeufin/transaction-identification.rst
deleted file mode 100644
index 6c88a727..00000000
--- a/libeufin/transaction-identification.rst
+++ /dev/null
@@ -1,87 +0,0 @@
-.. target audience: developer, core developer
-
-Transaction Identification
-##########################
-
-This page describes how bank transactions are **identified** in various banking protocols and
-data formats.
-
-**Why is transaction identification necessary?**
-When a client downloads the transaction history from some data source, it has to know
-whether a transaction is new, or whether the transaction is already part of the
-client's local records.
-
-Protocol-specific Details
-=========================
-
-ISO 20022 camt.05X
-------------------
-
-The camt52/53/54 messages defined by ISO 20022 do not have a mandatory transaction
-identifier. Instead it defines a handful of optional references.
-
-Two identifiers seem to be used in practice: The *Account Servicer Reference* and the
-*Entry Reference*. Of these, only the *Account Servicer Reference* seems to be useful
-for transaction identification.
-
-The Account Servicer Reference is assigned by the bank to a transaction. In
-practice, all banks assign the **same** Account Servicer Reference to the same
-transaction showing up in camt52 (the account report), camt53 (the account
-statement) and camt53 (credit notifications).
-
-The Account Servicer Reference is assigned by the bank that reports the transaction,
-and does **not** serve as a globally unique identifier for the transaction.
-
-However, in rare cases, a transaction can be reported that does not yet have an
-Account Servicer Reference assigned to it by the bank yet. This can happen
-when the bank only received a (SWIFT) pre-notification for the transaction, but decides
-to already pass on this information to the customer. In this case, banks seem to
-assign an *Entry Reference* to the corresponding entry.
-
-Most other transactions, however, do **not** have an *Entry Reference* assigned to it.
-Some banks document that the *Entry Reference* is only unique within one report for one account.
-
-OFX
----
-
-OFX assigns a transaction identifier to each reported transactions, allowing the client
-to know which transactions it has already seen.
-
-Problems and Possible Solutions
-===============================
-
-Sometimes the same bank can offer **multiple** ways to download transactions.
-In Germany, most banks offer EBICS and FinTS access, which delivers transactions
-in the camt.52/53 format. However, some also offer access via PSD2 APIs and completely custom APIs.
-
-Two APIs from the same bank do not necessarily need to support the same transaction identification scheme.
-This could lead to the same transaction showing up multiple times in the account transaction history, which
-is clearly bad!
-
-LibEuFin intends to solve this problem in the following ways:
-
-1. Each local account has a single "transaction identification scheme".
- Importing transactions via a bank connection that has a different transaction
- identifier scheme will fail.
-2. When a bank connection reports a transaction that is missing the expected transaction identifier,
- the status (booked, pending, info) is examined:
-
- 1. When the status is booked, an error is reported, and corresponding bank message
- will be made available for review.
- 2. When the status is "pending" or "info", the entry will simply be ignored.
-
-In the future, this might be extended to be less restrictive:
-
-* An account could be configured to do transaction identification based on a "core attributes hash",
- i.e. a cryptographic hash of core attributes of the transactions that are expected to not change.
- This should only apply to booked transactions.
-* Un-identifiable pending/info transactions could be managed in a separate
- "informational" transactions table that is purged as soon as a *booked statement closing transaction*
- is reported with a higher booking date.
-
-Others
-======
-
-* `UETR <https://www.swift.com/your-needs/industry-themes/unique-end-to-end-transaction-reference-uetr>`__ is
- a unique identifier used on the SWIFT level. It doesn't help for transaction identification
- as not every transaction goes over SWIFT, even for SEPA accounts.
diff --git a/manpages/TDM.el b/manpages/TDM.el
new file mode 100644
index 00000000..a58fb1c8
--- /dev/null
+++ b/manpages/TDM.el
@@ -0,0 +1,172 @@
+;;; TDM.el --- editing Taler docs.git/manpages/* -*- lexical-binding: t -*-
+
+;; Copyright (C) 2021, 2022 Taler Systems SA
+;;
+;; This file is part of GNU TALER.
+;;
+;; TALER 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.
+;;
+;; 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 Affero General Public License for more details.
+;;
+;; You should have received a copy of the GNU Affero General Public
+;; License along with TALER; see the file COPYING. If not, see
+;; <http://www.gnu.org/licenses/>.
+;;
+;; Author: Thien-Thi Nguyen <ttn@gnu.org>
+
+;;; Commentary:
+
+;; This library currently provides two commands: ‘TDM-convert-options’
+;; and ‘TDM-recursive-help’.
+;;
+;; * ‘TDM-convert-options’
+;; The intended workflow is simple:
+;; - Create a new file from template.
+;; - Do the <FOO> substitutions / deletions as necessary.
+;; - Split the window, one half for Synopsis, one for Description.
+;; - Do ‘COMMAND --help’ and copy the portion of its output that
+;; describes the options into the buffer in the Synopsis section.
+;; + Place point at bol of an option and call ‘TDM-convert-options’.
+;; (Personally, I locally bind this to ‘C-c C-o’.)
+;; - Set mark at point and move point to the end of the
+;; description text (for that option).
+;; - Kill the region (with ‘C-w’).
+;; - Switch to the other window, find a suitable place, and
+;; yank (with ‘C-y’) the text there.
+;; - Edit the description as necessary.
+;; - Loop from "+" until finished.
+;;
+;; At the end, you may have to delete some extra blank lines
+;; in the Synopsis section.
+;;
+;; ‘TDM-convert-options’ takes a prefix arg, which inhibits the
+;; deletion of the original (--help output) text. This can be
+;; useful if you don't trust (yet :-D) the conversion process.
+;;
+;; There are a couple TODO items, which point to situations that
+;; have not yet arisen in practice, but that might theoretically
+;; bother us in the future.
+;;
+;; * ‘TDM-recursive-help’
+;; This command is intended for libeufin programs, specifically
+;; libeufin-sandbox, libeufin-nexus, and libeufin-cli. However,
+;; it should work with any Java program that uses clikt, or any
+;; Python program that uses click, for its command-line handling.
+;;
+;; You can obtain the --help output (recursively) in a buffer
+;; and write it to a file for further analysis / processing.
+
+;;; Code:
+
+(require 'cl-lib)
+
+(defun TDM-parse-option-triple ()
+ "Return a triple formed by parsing option text at point.
+The triple has the form (ARG SHORT LONG), where each element
+can be either a string or ‘nil’.
+
+Signal error if parsing fails.
+Leave point after the end of the parsed text."
+ (cl-flet ((peer (regexp)
+ (re-search-forward regexp (line-end-position) t)))
+ (cond
+ ;; Full form: (ARG SHORT LONG).
+ ((peer " *-\\(.\\), --\\([^=\n]+\\)=\\(\\S +\\)")
+ (mapcar #'match-string-no-properties (list 3 1 2)))
+ ;; No argument: (nil SHORT LONG).
+ ((peer " *-\\(.\\), --\\(\\S +\\)")
+ (list nil
+ (match-string-no-properties 1)
+ (match-string-no-properties 2)))
+ ;; TODO: Handle other combinations.
+ (t
+ (error "Could not parse option text")))))
+
+(defun TDM-insert-options (arg short long)
+ "Insert formatted options, twice (on two lines).
+The first is for the Synopsis section, the second for Description."
+ (unless (zerop (current-column))
+ (open-line 1)
+ (forward-line 1))
+ (cl-flet ((ins (short-space sep)
+ (cond
+ ;; Both available.
+ ((and short long)
+ (insert "**-" short "**")
+ (when arg
+ (insert short-space "*" arg "*"))
+ (insert sep)
+ (insert "**--" long (if arg "=" "") "**")
+ (when arg
+ (insert "\\ \\ *" arg "*")))
+ ;; TODO: Handle other combinations.
+ (t
+ (error "Could not handle (%S %S %S)"
+ arg short long)))))
+ ;; First line.
+ (insert "[")
+ (ins " " " | ")
+ (insert "]\n")
+ ;; Second line. Leave point at its beginning.
+ (save-excursion
+ (ins " " " \\| ")
+ ;; Add a newline only if necessary.
+ (unless (eolp)
+ (insert "\n")))))
+
+(defun TDM-convert-options (&optional keep-orig)
+ "Grok the options at point and insert formatted ones.
+If successful, delete the parsed options as well.
+Prefix arg KEEP-ORIG means don't delete them."
+ (interactive "P")
+ (let* ((p (point))
+ (triple (TDM-parse-option-triple))
+ (q (point)))
+ (apply #'TDM-insert-options triple)
+ (unless keep-orig
+ (save-excursion
+ (delete-region p q)))))
+
+(defun TDM-recursive-help (command)
+ "Call COMMAND --help and recurse on its subcommands.
+Subcommands are identified by \"Commands:\" in column 0
+in the output.
+
+Collect the output in a new buffer *COMMAND --help*,
+with one page per --help output."
+ (interactive "sCommand: ")
+ (let ((out (get-buffer-create (format "*%s --help*" command))))
+ (with-current-buffer out
+ (erase-buffer))
+ (cl-labels
+ ;; visit command
+ ((v (c) (with-temp-buffer
+ (apply #'call-process (car c) nil t nil
+ (append (cdr c) (list "--help")))
+ (goto-char (point-min))
+ (when (re-search-forward "^Commands:\n" nil t)
+ (while (looking-at "[ ][ ]\\(\\S +\\)")
+ (let ((sub (match-string 1)))
+ (v (append c (list sub))))
+ (forward-line 1)
+ (while (looking-at "[ ][ ][ ]")
+ (forward-line 1))))
+ (let ((s (buffer-string)))
+ (message "c: %s" c)
+ (with-current-buffer out
+ (goto-char (point-min))
+ (insert "\f\n")
+ (insert "$ " (substring (format "%s" c) 1 -1) "\n")
+ (insert s "\n"))))))
+ (v (list command)))
+ (switch-to-buffer out)))
+
+(provide 'TDM)
+
+;;; TDM.el ends here
diff --git a/manpages/TEMPLATE-1 b/manpages/TEMPLATE-1
new file mode 100644
index 00000000..40debc7e
--- /dev/null
+++ b/manpages/TEMPLATE-1
@@ -0,0 +1,48 @@
+<COMMAND>(1)
+############
+
+.. only:: html
+
+ Name
+ ====
+
+ **<COMMAND>** - <ONE-LINE-DESCRIPTION>
+
+
+Synopsis
+========
+
+**<COMMAND>**
+[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
+[**-h** | **--help**]
+[**-v** | **--version**]
+
+
+Description
+===========
+
+**<COMMAND>** is a command-line tool to <ONE-LINE-DESCRIPTION>.
+
+Its options are as follows:
+
+**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
+ Use the configuration and other resources for the <PROGRAM>
+ to operate from *FILENAME*.
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-v** \| **–version**
+ Print version information.
+
+
+See Also
+========
+
+
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/challenger-admin.1.rst b/manpages/challenger-admin.1.rst
new file mode 100644
index 00000000..bdb7687c
--- /dev/null
+++ b/manpages/challenger-admin.1.rst
@@ -0,0 +1,70 @@
+challenger-admin(1)
+###################
+
+.. only:: html
+
+ Name
+ ====
+
+ **challenger-admin** - manipulate clients registered in Challenger database
+
+
+Synopsis
+========
+
+**challenger-admin**
+[**-a** *CLIENT_SECRET* | **--add=**\ \ *CLIENT_SECRET*]
+[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
+[**-d** | **--delete**]
+[**-h** | **--help**]
+[**-L** *LOGLEVEL* | **--log=**\ \ *LOGLEVEL*]
+[**-l** *FILENAME* | **--logfile=**\ \ *FILENAME*]
+[**-q** | **--quiet**]
+[**-v** | **--version**]
+CLIENT_URL
+
+
+Description
+===========
+
+**challenger-admin** is a command-line tool to add or delete clients from the Challenger database.
+
+Its options are as follows:
+
+**-a** *SECRET* \| **--add=**\ ‌\ *SECRET*
+ Add the client with the given *CLIENT_URL setting the client secret to *SECRET*. Prints the CLIENT_ID of the added client.
+
+**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
+ Use the configuration and other resources for the Challenger commands
+ to operate from *FILENAME*.
+
+**-d** \| **--delete**
+ Delete the client with the given *CLIENT_URL*.
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-L** *LOGLEVEL* \| **--log=**\ \ *LOGLEVEL*
+ Configure logging to use *LOGLEVEL*.
+
+**-l** *FILENAME* \| **--logfile=**\ \ *FILENAME*
+ Configure logging to write logs to *FILENAME*.
+
+**-q** \| **–-quiet**
+ Be less verbose in the output. Useful in shell scripts.
+
+**-v** \| **–-version**
+ Print version information.
+
+
+See Also
+========
+
+challenger-config(1), challenger-httpd(1), challenger.conf(5).
+
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/challenger-config.1.rst b/manpages/challenger-config.1.rst
new file mode 100644
index 00000000..16ba7bb7
--- /dev/null
+++ b/manpages/challenger-config.1.rst
@@ -0,0 +1,101 @@
+challenger-config(1)
+####################
+
+.. only:: html
+
+ Name
+ ====
+
+ **challenger-config** - manipulate Challenger configuration file
+
+Synopsis
+========
+
+**challenger-config**
+[**-b** *backend* | **--supported-backend=**\ \ *backend*]
+[**-c** *filename* | **--config=**\ \ *filename*]
+[**-f** | **--filename**]
+[**-F** | **--full**]
+[**-h** | **--help**]
+[**-L** *loglevel* | **--loglevel=**\ \ *loglevel*]
+[**-l** *filename* | **--logfile=**\ ‌\ *filename*]
+[**-o** *option* | **--option=**\ \ *option*]
+[**-r** | **--rewrite**]
+[**-S** | **--list-sections**]
+[**-s** *section* | **--section=**\ \ *section*]
+[**-V** *value* | **--value=**\ \ *value*]
+[**-v** | **--version**]
+
+
+Description
+===========
+
+**challenger-config** can be used to read or modify Challenger configuration files.
+
+**-b** *BACKEND* \| **--supported-backend=**\ \ *BACKEND*
+ Tests whether the specified *BACKEND* is supported by the current installation.
+ The backend must match the name of a plugin, i.e. "namestore_postgres" for
+ the PostgreSQL database backend of the "NAMESTORE" service. If *BACKEND* is
+ supported, challenger-config will return a status code of 0 (success), otherwise
+ 77 (unsupported). When this option is specified, no other options may be
+ specified. Specifying this option together with other options will cause
+ challenger-config to return a status code of 1 (error).
+
+**-c** *FILENAME* \| **--config=**\ \ *FILENAME*
+ Use the configuration file *FILENAME*.
+
+**-f** \| **--filename**
+ Try to perform expansions as if the option values represent filenames (will
+ also be applied even if the option is not really a filename).
+
+**-F** \| **--full**
+ Write the full configuration file, not just the differences to the defaults.
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-L** *LOGLEVEL* \| **--loglevel=**\ \ *LOGLEVEL*
+ Use *LOGLEVEL* for logging.
+ Valid values are ``DEBUG``, ``INFO``, ``WARNING``, and ``ERROR``.
+
+**-l** *FILENAME* \| **--logfile=**\ ‌\ *FILENAME*
+ Send logging output to *FILENAME*.
+
+**-o** *OPTION* \| **--option=**\ \ *OPTION*
+ Which configuration option should be accessed or edited. Required to set a
+ value. If not given, all values of a given section will be printed in the
+ format "OPTION = VALUE".
+
+**-r** \| **--rewrite**
+ Write the configuration file even if nothing changed. Will remove all comments!
+
+**-S** \| **--list-sections**
+ List available configuration sections for use with ``--section``.
+
+**-s** *SECTION* \| **--section=**\ \ *SECTION*
+ Which configuration section should be accessed or edited.
+ Required option.
+
+**-V** *VALUE* \| **--value=**\ \ *VALUE*
+ Configuration value to store in the given section under the given option.
+ Must only be given together with ``-s`` and ``-o`` options.
+
+ Note:
+ Changing the configuration file with ``-V`` will remove comments
+ and may reorder sections and remove ``@INLINE@`` directives.
+
+**-v** \| **--version**
+ Print GNU Taler version number.
+
+
+See Also
+========
+
+challenger-dbinit(1), challenger-httpd(1), challenger.conf(5).
+
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/challenger-dbconfig.1.rst b/manpages/challenger-dbconfig.1.rst
new file mode 100644
index 00000000..da69eeaf
--- /dev/null
+++ b/manpages/challenger-dbconfig.1.rst
@@ -0,0 +1,61 @@
+challenger-dbconfig(1)
+######################
+
+.. only:: html
+
+ Name
+ ====
+
+ **challenger-dbconfig** - configure challenger database
+
+
+Synopsis
+========
+
+**challenger-dbconfig**
+[**-c** *FILENAME*]
+[**-h**]
+[**-n** *NAME*]
+[**-r**]
+[**-s**]
+[**-u** *USER*]
+
+Description
+===========
+
+**challenger-dbconfig** is a simple shell script that configures
+a Postgresql database for use by ``challenger-httpd``.
+
+Its options are as follows:
+
+**-c** *FILENAME*
+ Write the database configuration to FILENAME. The tool
+ will append the required ``CONFIG`` option for the
+ Postgresql access to the respective file.
+
+**-h**
+ Print short help on options.
+
+**-n** *DBNAME*
+ Use DBNAME for the name of the created database.
+
+**-r**
+ Reset any existing database. Looses all existing data. DANGEROUS.
+
+**-s**
+ Skip database initialization. Useful if you want to run
+ ``challenger-dbinit`` manually.
+
+**-u** *USER*
+ Specifies the (main) challenger user that will access the database.
+
+See Also
+========
+
+challenger-dbinit(1), challenger.conf(5).
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/challenger-dbinit.1.rst b/manpages/challenger-dbinit.1.rst
new file mode 100644
index 00000000..5200c661
--- /dev/null
+++ b/manpages/challenger-dbinit.1.rst
@@ -0,0 +1,65 @@
+challenger-dbinit(1)
+####################
+
+.. only:: html
+
+ Name
+ ====
+
+ **challenger-dbinit** - initialize the Challenger database
+
+
+Synopsis
+========
+
+**challenger-dbinit**
+[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
+[**-g** | **--garbagecollect**]
+[**-h** | **--help**]
+[**-L** *LOGLEVEL* | **--log=**\ \ *LOGLEVEL*]
+[**-l** *FILENAME* | **--logfile=**\ \ *FILENAME*]
+[**-r** | **--reset**]
+[**-v** | **--version**]
+
+
+Description
+===========
+
+**challenger-dbinit** is a command-line tool to initialize the Challenger database.
+
+Its options are as follows:
+
+**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
+ Use the configuration and other resources for the Challenger commands
+ to operate from *FILENAME*.
+
+**-g** \| **--garbagecollect**
+ Remove state data from database.
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-L** *LOGLEVEL* \| **--log=**\ \ *LOGLEVEL*
+ Configure logging to use *LOGLEVEL*.
+
+**-l** *FILENAME* \| **--logfile=**\ \ *FILENAME*
+ Configure logging to write logs to *FILENAME*.
+
+**-r** \| **--reset**
+ Reset database. (**DANGEROUS**: All existing data is lost!)
+
+**-v** \| **–version**
+ Print version information.
+
+
+See Also
+========
+
+challenger-config(1), challenger-httpd(1), challenger.conf(5).
+
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/challenger-httpd.1.rst b/manpages/challenger-httpd.1.rst
new file mode 100644
index 00000000..0bc08486
--- /dev/null
+++ b/manpages/challenger-httpd.1.rst
@@ -0,0 +1,61 @@
+challenger-httpd(1)
+###################
+
+.. only:: html
+
+ Name
+ ====
+
+ **challenger-httpd** - provide the Challenger HTTP interface
+
+
+Synopsis
+========
+
+**challenger-httpd**
+[**-C** | **--connection-close**]
+[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
+[**-h** | **--help**]
+[**-L** *LOGLEVEL* | **--log=**\ \ *LOGLEVEL*]
+[**-l** *FILENAME* | **--logfile=**\ \ *FILENAME*]
+[**-v** | **--version**]
+
+
+Description
+===========
+
+**challenger-httpd** is a command-line tool to provide the Challenger HTTP interface.
+
+Its options are as follows:
+
+**-C** \| **--connection-close**
+ Force HTTP connections to be closed after each request.
+
+**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
+ Use the configuration and other resources for the Challenger commands
+ to operate from *FILENAME*.
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-L** *LOGLEVEL* \| **--log=**\ \ *LOGLEVEL*
+ Configure logging to use *LOGLEVEL*.
+
+**-l** *FILENAME* \| **--logfile=**\ \ *FILENAME*
+ Configure logging to write logs to *FILENAME*.
+
+**-v** \| **–version**
+ Print version information.
+
+
+See Also
+========
+
+challenger-config(1), challenger-dbinit(1), challenger.conf(5).
+
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/challenger.conf.5.rst b/manpages/challenger.conf.5.rst
new file mode 100644
index 00000000..626d11f7
--- /dev/null
+++ b/manpages/challenger.conf.5.rst
@@ -0,0 +1,88 @@
+challenger.conf(5)
+##################
+
+.. only:: html
+
+ Name
+ ====
+
+ **challenger.conf** - Challenger configuration file
+
+
+Description
+===========
+
+.. include:: ../frags/common-conf-syntax.rst
+
+Files containing default values for many of the options described below
+are installed under ``$PREFIX/share/challenger/config.d/``.
+The configuration file given with **-c** to Challenger binaries
+overrides these defaults.
+
+A configuration file may include another, by using the ``@INLINE@`` directive,
+for example, in ``main.conf``, you could write ``@INLINE@ sub.conf`` to
+include the entirety of ``sub.conf`` at that point in ``main.conf``.
+
+Be extra careful when using ``challenger-config -V VALUE`` to change configuration
+values: it will destroy all uses of ``@INLINE@`` and furthermore remove all
+comments from the configuration file!
+
+
+GLOBAL OPTIONS
+--------------
+
+The following options are from the “[challenger]” section.
+This is normally the only section in a challenger.conf file.
+
+SERVE
+ This can either be ``tcp`` or ``unix``.
+
+PORT
+ Port on which the HTTP server listens, e.g. 9967.
+ Only used if ``SERVE`` is ``tcp``.
+
+BIND_TO
+ Which IP address should we bind to? E.g. ``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``.
+
+UNIXPATH
+ Which unix domain path should we bind to?
+ Only used if ``SERVE`` is ``unix``.
+
+UNIXPATH_MODE = 660
+ What should be the file access permissions for ``UNIXPATH``?
+ Only used if ``SERVE`` is ``unix``.
+
+DB
+ Plugin to use for the database, e.g. “postgres”.
+
+VALIDATION_DURATION
+ How long is a validation challenge valid. After this time period, a fresh random challenge code will be generated and the retry limit counter (against guessing attacks) will be reset (to 3).
+
+VALIDATION_EXPIRATION
+ How long is a validation allowed to take (time from
+ ``/setup`` to ``/token``). After this time, the garbage collection process can delete all associated data. (Note that tokens will always allow access to 1h after they have been issued, regardless of when the validation expires).
+
+AUTH_COMMAND
+ Which command should we execute to transmit the challenge code to the address. The address is given as the first argument, while the message to send is provided on stdin. Templates (possibly without the necessary credentials) for such commands are provided as challenger-send-email.sh, challenger-send-post.sh and challenger-send-sms.sh.
+
+ADDRESS_TYPE
+ Type of the address that is being collected, returned as part of the ``address_type`` in the ``/info`` endpoint. Examples include ``email`` or ``phone``.
+
+ADDRESS_RESTRICTIONS
+ JSON object with a map of keys (names of the fields of the address to be entered by the user) to objects with a "regex" (string) containing an extended Posix regular expression for allowed address field values, and a "hint"/"hint_i18n" giving a human-readable explanation to display if the value entered by the user does not match the regex. Keys that are not mapped to such an object have no restriction on the value provided by the user. Examples would be '{"email":{"hint":"valid e-mail address required","regex":"^[a-zA-Z0-9\_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"}' or '{"zip":{"hint":"numeric zip code required","regex":"^[0-9]+$"}'.
+
+
+SEE ALSO
+========
+
+challenger-dbinit(1), challenger-httpd(1), challenger-config(1).
+
+
+BUGS
+====
+
+Report bugs by using https://bugs.taler.net/ or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/libeufin-bank.1.rst b/manpages/libeufin-bank.1.rst
new file mode 100644
index 00000000..77bc1104
--- /dev/null
+++ b/manpages/libeufin-bank.1.rst
@@ -0,0 +1,185 @@
+libeufin-bank(1)
+#################
+
+.. only:: html
+
+ Name
+ ====
+
+ **libeufin-bank** - LibEuFin Bank
+
+
+Synopsis
+========
+
+**libeufin-bank**
+[**-h** | **--help**]
+[**--version**]
+COMMAND [ARGS...]
+
+Subcommands: **serve**, **dbinit**, **create-account**, **passwd**, **gc**,
+**config**
+
+
+Description
+===========
+
+**libeufin-bank** is a program that implements a simple core banking system with
+account and REST APIs, including REST APIs for a Web interface
+and REST APIs to interact with GNU Taler components.
+
+Its options are as follows:
+
+**-h** \| **--help**
+ Print short help on options.
+
+**–version**
+ Print version information.
+
+The interaction model is as follows:
+
+- Configure the database with commands ``dbinit``.
+
+- Set admin account password with commands ``passwd``.
+
+- Start the HTTP server with command ``serve``.
+ Let this run in a shell, writing logs to stderr.
+
+The following sections describe each command in detail.
+
+dbinit
+------
+
+This command defines the database schema for LibEuFin Bank. It is mandatory to run this command before invoking the ``serve`` command.
+
+Its options are as follows:
+
+**-h** \| **--help**
+ Print short help on options.
+**-c** \| **--config** *FILENAME*
+ Specifies the configuration file.
+**-L** \| **--log** *LOGLEVEL*
+ Configure logging to use LOGLEVEL.
+**-r** \| **--reset**
+ If present, deletes any database table (WARNING: potential data loss)
+
+
+serve
+-----
+
+This command starts the HTTP server.
+
+Its options are as follows:
+
+**-h** \| **--help**
+ Print short help on options.
+**-c** \| **--config** *FILENAME*
+ Specifies the configuration file.
+**-L** \| **--log** *LOGLEVEL*
+ Configure logging to use LOGLEVEL.
+
+create-account
+--------------
+
+This command create a bank account and prints its payto://-URI to STDOUT.
+
+Its options are as follows:
+
+**-h** \| **--help**
+ Print short help on options.
+**-c** \| **--config** *FILENAME*
+ Specifies the configuration file.
+**-L** \| **--log** *LOGLEVEL*
+ Configure logging to use LOGLEVEL.
+**-u** \| **--username** *USERNAME*
+ Account unique username.
+**-p** \| **--password** *PASSWORD*
+ Account password used for authentication.
+**--name** *NAME*
+ Legal name of the account owner.
+**--public**
+ Make this account visible to anyone.
+**--exchange**
+ Make this account a taler exchange.
+**--email** *EMAIL*
+ E-Mail address used for TAN transmission.
+**--phone** *PHONE_NUMBER*
+ Phone number used for TAN transmission.
+**--cashout_payto_uri** *PAYTO_URI*
+ Payto URI of a fiant account who receive cashout amount.
+**--payto_uri** *PAYTO_URI*
+ Payto URI of this account.
+**--debit_threshold** *AMOUNT*
+ Max debit allowed for this account.
+
+
+edit-account
+--------------
+
+This command edit an existing account.
+
+It takes one argument, the account username.
+
+Its options are as follows:
+
+**-h** \| **--help**
+ Print short help on options.
+**-c** \| **--config** *FILENAME*
+ Specifies the configuration file.
+**-L** \| **--log** *LOGLEVEL*
+ Configure logging to use LOGLEVEL.
+**--name** *NAME*
+ Legal name of the account owner.
+**--public** *true|false*
+ Make this account visible to anyone.
+**--email** *EMAIL*
+ E-Mail address used for TAN transmission.
+**--phone** *PHONE_NUMBER*
+ Phone number used for TAN transmission.
+**--cashout_payto_uri** *PAYTO_URI*
+ Payto URI of this account.
+**--debit_threshold** *AMOUNT*
+ Max debit allowed for this account.
+
+passwd
+------
+
+This command change any account password.
+
+It takes two arguments, the account username and the account new password.
+
+Its options are as follows:
+
+**-h** \| **--help**
+ Print short help on options.
+**-c** \| **--config** *FILENAME*
+ Specifies the configuration file.
+**-L** \| **--log** *LOGLEVEL*
+ Configure logging to use LOGLEVEL.
+
+gc
+--
+
+This command performs garbage collection: abort expired operations and clean expired data, etc.
+
+Its options are as follows:
+
+**-h** \| **--help**
+ Print short help on options.
+**-c** \| **--config** *FILENAME*
+ Specifies the configuration file.
+**-L** \| **--log** *LOGLEVEL*
+ Configure logging to use LOGLEVEL.
+
+.. include:: ../frags/libeufin-config-cli.rst
+
+
+SEE ALSO
+========
+
+libeufin-bank.conf(5)
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic mail to <taler@gnu.org>.
diff --git a/manpages/libeufin-bank.conf.5.rst b/manpages/libeufin-bank.conf.5.rst
new file mode 100644
index 00000000..ce00f0fa
--- /dev/null
+++ b/manpages/libeufin-bank.conf.5.rst
@@ -0,0 +1,146 @@
+libeufin-bank.conf(5)
+######################
+
+.. only:: html
+
+ Name
+ ====
+
+ **libeufin-bank.conf** - LibEuFin Bank configuration file
+
+
+Description
+===========
+
+.. include:: ../frags/common-conf-syntax.rst
+
+Files containing default values for many of the options described below
+are installed under ``$TALER_PREFIX/share/libeufin-bank/config.d/``.
+The configuration file given with **-c** to Taler binaries
+overrides these defaults.
+
+A configuration file may include another, by using the ``@INLINE@`` directive,
+for example, in ``main.conf``, you could write ``@INLINE@ sub.conf`` to
+include the entirety of ``sub.conf`` at that point in ``main.conf``.
+
+Be extra careful when using ``taler-config -V VALUE`` to change configuration
+values: it will destroy all uses of ``@INLINE@`` and furthermore remove all
+comments from the configuration file!
+
+GLOBAL OPTIONS
+--------------
+
+The following options are from the “[libeufin-bank]” section.
+
+CURRENCY
+ Internal currency of the libeufin-bank, e.g. “EUR” for Euro.
+
+WIRE_TYPE
+ Supported payment target type, this can either be ``iban`` or ``x-taler-bank``
+
+IBAN_PAYTO_BIC
+ Bank BIC used in generated iban payto URI. Required if ``WIRE_TYPE``is ``iban``
+
+X_TALER_BANK_PAYTO_HOSTNAME
+ Bank hostname used in generated x-taler-bank payto URI. Required if ``WIRE_TYPE``is ``x-taler-bank``
+
+NAME
+ Bank display name, used in webui and TAN messages. Default to ``Taler Bank`` if not specified.
+
+BASE_URL
+ The advertised base URL
+
+DEFAULT_DEBT_LIMIT
+ Default debt limit for newly created accounts. Defaults to ``CURRENCY:0`` if not specified.
+
+REGISTRATION_BONUS
+ Value of the registration bonus for new users. Defaults to ``CURRENCY:0`` if not specified.
+
+ALLOW_REGISTRATION
+ Whether anyone can create a new account or whether this action is reserved for the admin. Defaults to ``NO`` if not specified.
+
+ALLOW_ACCOUNT_DELETION
+ Whether anyone can delete its account or whether this action is reserved for the admin. Defaults to ``NO`` if not specified.
+
+ALLOW_EDIT_NAME
+ Whether anyone can edit their legal name or whether this action is reserved for the admin. Defaults to ``NO`` if not specified.
+
+ALLOW_EDIT_CASHOUT_PAYTO_URI
+ Whether anyone can edit their cashout account or whether this action is reserved for the admin. Defaults to ``NO`` if not specified.
+
+ALLOW_CONVERSION
+ Whether regional currency conversion is enabled. Defaults to ``NO`` if not specified.
+
+FIAT_CURRENCY
+ External currency used during cashin and cashout.
+ Only used if ``ALLOW_CONVERSION`` is ``YES``.
+
+TAN_SMS
+ Path to TAN challenge transmission script via sms. If not specified, this TAN channel will not be supported.
+ Only used if ``ALLOW_CONVERSION`` is ``YES``.
+
+TAN_EMAIL
+ Path to TAN challenge transmission script via email. If not specified, this TAN channel will not be supported.
+ Only used if ``ALLOW_CONVERSION`` is ``YES``.
+
+TAN_SMS_ENV
+ Environment variables for the sms TAN script.
+ Only used if ``TAN_SMS`` is set.
+
+TAN_EMAIL_ENV
+ Environment variables for the email TAN script.
+ Only used if ``TAN_EMAIL`` is set.
+
+SERVE
+ This can either be ``tcp`` or ``unix``.
+
+PORT
+ Port on which the HTTP server listens, e.g. 9967.
+ Only used if ``SERVE`` is ``tcp``.
+
+BIND_TO
+ Which IP address should we bind to? E.g. ``127.0.0.1`` or ``::1``for loopback. Can also be given as a hostname.
+ Only used if ``SERVE`` is ``tcp``.
+
+UNIXPATH
+ Which unix domain path should we bind to?
+ Only used if ``SERVE`` is ``unix``.
+
+UNIXPATH_MODE
+ What should be the file access permissions for ``UNIXPATH``?
+ Only used if ``SERVE`` is ``unix``.
+
+SUGGESTED_WITHDRAWAL_EXCHANGE
+ Exchange that is suggested to wallets when withdrawing
+
+GC_ABORT_AFTER
+ Time after which pending operations are aborted during garbage collection
+
+GC_CLEAN_AFTER
+ Time after which aborted operations and expired items are deleted during garbage collection
+
+GC_DELETE_AFTER
+ Time after which all bank transactions, operations and deleted accounts are deleted during garbage collection
+
+DATABASE OPTIONS
+----------------
+
+Setting the database belongs to the “[libeufin-bankdb-postgres]” section and the
+following value.
+
+CONFIG
+ PostgreSQL connection string.
+
+SQL_DIR
+ Where are the SQL files to setup our tables?
+
+SEE ALSO
+========
+
+libeufin-bank(1).
+
+BUGS
+====
+
+Report bugs by using https://bugs.taler.net/ or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/libeufin-nexus.1.rst b/manpages/libeufin-nexus.1.rst
new file mode 100644
index 00000000..a0ed99ff
--- /dev/null
+++ b/manpages/libeufin-nexus.1.rst
@@ -0,0 +1,154 @@
+libeufin-nexus(1)
+#################
+
+.. only:: html
+
+ Name
+ ====
+
+ **libeufin-nexus** - EBICS client.
+
+
+Synopsis
+========
+
+**libeufin-nexus**
+[**-h** | **--help**]
+[**--version**]
+COMMAND [ARGS...]
+
+Subcommands: **dbinit**, **ebics-setup**, **ebics-submit**, **ebics-fetch**, **config**
+
+
+Description
+===========
+
+**libeufin-nexus** is a program that provides a service to interface to
+various bank access APIs
+
+Its options are as follows:
+
+**-h** \| **--help**
+ Print short help on options.
+
+**–version**
+ Print version information.
+
+The interaction model is as follows:
+
+In order to operate any EBICS communication with ``libeufin-nexus``, it is necessary to setup EBICS access via the ``ebics-setup`` subcommand. Setting the access means to share the client keys with the bank and downloading the bank keys. After a successful setup, the subcommands ``ebics-submit`` and ``ebics-fetch`` can be run to respectively send payments and download the bank account history.
+
+The following sections describe each command in detail.
+
+ebics-setup
+-----------
+
+This command creates the client keys, if they aren't found already on the disk, and sends them to the bank if they were not sent yet. In case of sending, it ejects the PDF document that contains the keys fingerprints, so that the user can send it to the bank to confirm their keys. The process continues by checking if the bank keys exist already on disk, and proceeds with downloading them in case they are not. It checks then if the bank keys were accepted by the user; if yes, the setup terminates, otherwise it interactively asks the user to mark the keys as accepted. By accepting the bank keys, the setup terminates successfully.
+
+Its options are as follows:
+
+**-h** \| **--help**
+ Print short help on options.
+**-c** \| **--config** *FILENAME*
+ Specifies the configuration file.
+**-L** \| **--log** *LOGLEVEL*
+ Configure logging to use LOGLEVEL.
+**--force-keys-resubmission**
+ Resubmits the client keys. If no keys were found, it creates and submits them.
+**--auto-accept-keys**
+ Accepts the bank keys without interactively asking the user.
+**--generate-registration-pdf**
+ Generates the PDF with the client keys fingerprints, if the keys have the submitted state. That's useful in case the PDF went lost after the first submission and the user needs a new PDF.
+
+
+dbinit
+------
+
+This subcommand defines the database schema for Nexus. It is mandatory to run this command before invoking the ``ebics-submit`` or ``ebics-fetch`` subcommands.
+
+Its options are as follows:
+
+**-h** \| **--help**
+ Print short help on options.
+**-c** \| **--config** *FILENAME*
+ Specifies the configuration file.
+**-L** \| **--log** *LOGLEVEL*
+ Configure logging to use LOGLEVEL.
+**-r** \| **--reset**
+ If present, deletes any database table (WARNING: potential data loss)
+
+
+ebics-submit
+------------
+
+This subcommand submits any initiated payment that was not already sent to the bank. In the current version, initiated payments may come from a cash-out operation or from a bounced incoming payment. ebics-submit is Taler friendly, therefore bounced payments are those that do not contain a valid subject to start a Taler withdrawal. Cash-out operations come from a tightly integrated bank that offers their customers to convert their currency to the currency whose the EBICS subscriber bank account is tied to.
+
+Its options are as follows:
+
+**-h** \| **--help**
+ Print short help on options.
+**-c** \| **--config** *FILENAME*
+ Specifies the configuration file.
+**-L** \| **--log** *LOGLEVEL*
+ Configure logging to use LOGLEVEL.
+ Uploaded documents will be stored *before* being submitted to the bank. This directory would contain several directories, each named after the ``YYYY-MM-DD/submit`` format. The pain.001 file would then be named in the following schema: ``$microseconds_pain.001.xml``.
+**--transient**
+ This flag, enabled by default, causes the command to check the database and submit only once, and then return.
+
+
+ebics-fetch
+-----------
+
+This subcommand downloads and parse EBICS files and ingest them into the database. Along the download, ebics-fetch would bounce incoming payments that do not have a valid Taler subject, or as well those with an already existing valid subject. Valid incoming payments are then stored in the database so that they can trigger Taler withdrawals. Along this process, ebics-submit would as well reconcile initiated outgoing payments with any outgoing transactions that show up in the downloaded records.
+
+The files type can be given as an argument to select what will be fetched. If no argument is given, all supported files are fetched. The following files are supported:
+
+* ``acknowledgement``: EBICS acknowledgement, retrieves the status of EBICS orders.
+* ``status``: Payment status, retrieves status of pending debits.
+* ``notification``: Debit & credit notifications, retrieves the history of confirmed debits and credits.
+
+**-h** \| **--help**
+ Print short help on options.
+**-c** \| **--config** *FILENAME*
+ Specifies the configuration file.
+**-L** \| **--log** *LOGLEVEL*
+ Configure logging to use LOGLEVEL.
+**--debug-ebics** *SAVEDIR*
+ Log EBICS content at SAVEDIR.
+ Downloaded documents will be stored *before* being ingested in the database. This directory would contain several directories, each named after the ``YYYY-MM-DD/fetch`` format. The stored files would then be named after the following schema: ``$microseconds_$filename``. Exception to this naming scheme are the HAC responses, since they do not get any filename assigned by the ZIP archive (they are sent unzipped). Their naming scheme is: ``$microseconds_HAC_response.pain.002.xml``.
+**--transient**
+ This flag, enabled by default, causes the command to perform one download and return.
+**--pinned-start**
+ Only supported in --transient mode, this option lets specify the earliest timestamp of the downloaded documents. The latest timestamp is always the current time.
+
+initiate-payment
+----------------
+
+This subcommand initiates an outgoing payment. The pending payment is stored in the database and will be performed the next time ``ebics-submit`` run.
+
+It takes one argument, the creditor IBAN payto URI, which must contain a 'receiver-name' and may contain an 'amount' and a 'message' if they have not been defined using CLI options.
+
+**-h** \| **--help**
+ Print short help on options.
+**-c** \| **--config** *FILENAME*
+ Specifies the configuration file.
+**-L** \| **--log** *LOGLEVEL*
+ Configure logging to use LOGLEVEL.
+**--amount** *AMOUNT*
+ The amount to transfer, payto 'amount' parameter takes the precedence
+**--subject** *TEXT*
+ The payment subject, payto 'message' parameter takes the precedence
+**--request-uid** *TEXT*
+ The payment request UID, will be randomly generated if missing.
+
+.. include:: ../frags/libeufin-config-cli.rst
+
+SEE ALSO
+========
+
+libeufin-nexus.conf(5)
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic mail to <taler@gnu.org>.
diff --git a/manpages/libeufin-nexus.conf.5.rst b/manpages/libeufin-nexus.conf.5.rst
new file mode 100644
index 00000000..9100f8fe
--- /dev/null
+++ b/manpages/libeufin-nexus.conf.5.rst
@@ -0,0 +1,190 @@
+libeufin-nexus.conf(5)
+######################
+
+.. only:: html
+
+ Name
+ ====
+
+ **libeufin-nexus.conf** - LibEuFin Nexus configuration file
+
+
+Description
+===========
+
+The configuration file is line-oriented. Blank lines and whitespace at the
+beginning and end of a line are ignored. Comments start with ``#`` or ``%``
+in the first column (after any beginning-of-line whitespace) and go to the end
+of the line.
+
+The file is split into sections. Every section begins with ``[SECTIONNAME]``
+and contains a number of options of the form ``OPTION=VALUE``. There may be
+whitespace around the ``=`` (equal sign). Section names and options are
+*case-insensitive*.
+
+The values, however, are *case-sensitive*. In particular, boolean values are
+one of ``YES`` or ``NO``. Values can include whitespace by surrounding the
+entire value with ``"`` (double quote). Note, however, that there are no
+escape characters in such strings; all characters between the double quotes
+(including other double quotes) are taken verbatim.
+
+Durations must be expressed with a number followed by the time unit. The following
+time units are supported: 's' (seconds), 'm' (minutes), 'h' (hours). For example,
+the value *5m* denotes a duration of *five minutes*.
+
+Values that represent filenames can begin with a ``/bin/sh``-like variable
+reference. This can be simple, such as ``$TMPDIR/foo``, or complex, such as
+``${TMPDIR:-${TMP:-/tmp}}/foo``. The variables are expanded either using
+key-values from the ``[PATHS]`` section (see below) or from the environment
+(``getenv()``). The values from ``[PATHS]`` take precedence over those from
+the environment. If the variable name is found in neither ``[PATHS]`` nor the
+environment, a warning is printed and the value is left unchanged. Variables (including those from the environment) are expanded recursively, so if ``FOO=$BAR`` and ``BAR=buzz`` then the result is ``FOO=buzz``. Recursion is bounded to at most 128 levels to avoid undefined behavior for mutually recursive expansions like if ``BAR=$FOO`` in the example above.
+
+The ``[PATHS]`` section is special in that it contains paths that can be
+referenced using ``$`` in other configuration values that specify
+*filenames*. Note that configuration options that are not specifically
+retrieved by the application as *filenames* will not see “$”-expressions
+expanded. To expand ``$``-expressions when using ``taler-config``, you must pass
+the ``-f`` command-line option.
+
+The system automatically pre-populates the ``[PATHS]`` section with a few values
+at run-time (in addition to the values that are in the actual configuration
+file and automatically overwriting those values if they are present).
+These automatically generated values refer to installation properties
+from `GNU autoconf
+<https://www.gnu.org/prep/standards/html_node/Directory-Variables.html>`_. The
+values are usually dependent on an ``INSTALL_PREFIX`` which is determined by
+the ``--prefix`` option given to configure. The canonical values are:
+
+ * LIBEXECDIR = $INSTALL_PREFIX/taler/libexec/
+ * DOCDIR = $INSTALL_PREFIX/share/doc/taler/
+ * ICONDIR = $INSTALL_PREFIX/share/icons/
+ * LOCALEDIR = $INSTALL_PREFIX/share/locale/
+ * PREFIX = $INSTALL_PREFIX/
+ * BINDIR = $INSTALL_PREFIX/bin/
+ * LIBDIR = $INSTALL_PREFIX/lib/taler/
+ * DATADIR = $INSTALL_PREFIX/share/taler/
+
+Note that on some platforms, the given paths may differ depending
+on how the system was compiled or installed, the above are just the
+canonical locations of the various resources. These
+automatically generated values are never written to disk.
+
+Files containing default values for many of the options described below
+are installed under ``$TALER_PREFIX/share/libeufin-nexus/config.d/``.
+The configuration file given with **-c** to Taler binaries
+overrides these defaults.
+
+A configuration file may include another, by using the ``@INLINE@`` directive,
+for example, in ``main.conf``, you could write ``@INLINE@ sub.conf`` to
+include the entirety of ``sub.conf`` at that point in ``main.conf``.
+
+Be extra careful when using ``taler-config -V VALUE`` to change configuration
+values: it will destroy all uses of ``@INLINE@`` and furthermore remove all
+comments from the configuration file!
+
+GLOBAL OPTIONS
+--------------
+
+Setting the database belongs to the “[nexus-postgres]” section and the
+following value.
+
+CONFIG
+ PostgreSQL connection string. Note: this option is NOT used by the
+ ebics-setup subcommand, as it stores the key files directly on the
+ filesystem.
+
+The “[paths]” section is special in that it contains paths that can be
+referenced using “$” in other configuration values that specify
+filenames. For Taler, it commonly contains the following paths:
+
+LIBEUFIN_HOME
+ Home directory of the user, usually “${HOME}”. Can be overwritten by
+ testcases by setting ${LIBEUFIN_TEST_HOME}.
+
+EBICS SETUP OPTIONS
+-------------------
+
+The following options are from the “[nexus-ebics]” section and used by
+the ``libeufin-nexus ebics-setup`` command.
+
+CURRENCY
+ Name of the currency, e.g. “EUR” for Euro.
+
+HOST_BASE_URL
+ URL of the EBICS server
+
+BANK_DIALECT
+ Name of the following combination: EBICS version and ISO20022 recommendations
+ that Nexus would honor in the communication with the bank. Currently only the
+ 'postfinance' value is supported.
+
+HOST_ID
+ EBICS specific: name of the EBICS host
+
+USER_ID
+ EBICS specific: user ID of the EBICS subscriber. This value must be assigned
+ by the bank after having activated a new EBICS subscriber.
+
+PARTNER_ID
+ EBICS specific: partner ID of the EBICS subscriber. This value must be assigned
+ by the bank after having activated a new EBICS subscriber.
+
+BANK_PUBLIC_KEYS_FILE
+ Filesystem location where Nexus should store the bank public keys.
+
+CLIENT_PRIVATE_KEYS_FILE
+ Filesystem location where Nexus should store the subscriber private keys.
+
+IBAN
+ IBAN of the bank account that is associated with the EBICS subscriber.
+
+BIC
+ BIC of the bank account that is associated with the EBICS subscriber.
+
+NAME
+ Legal entity that is associated with the EBICS subscriber.
+
+
+EBICS SUBMIT OPTIONS
+--------------------
+
+The following configuration value(s) belong to the “[nexus-submit]” section.
+
+FREQUENCY
+ Duration value to instruct the ``ebics-submit`` subcommand how much to wait
+ before checking the database again to find new unsubmitted payments.
+
+EBICS FETCH OPTIONS
+-------------------
+
+The following configuration value(s) belong to the “[nexus-fetch]” section.
+
+FREQUENCY
+ Duration value to instruct the ``ebics-fetch`` subcommand how often it should
+ download from the bank.
+
+IGNORE_TRANSACTIONS_BEFORE
+ Ignore all transactions before a certain YYYY-MM-DD date, useful when you want to use an existing account with old transactions that should not be bounced.
+
+DATABASE OPTIONS
+----------------
+
+Setting the database belongs to the “[libeufin-nexusdb-postgres]” section and the following value.
+
+CONFIG
+ PostgreSQL connection string.
+
+SQL_DIR
+ Where are the SQL files to setup our tables?
+
+SEE ALSO
+========
+
+libeufin-nexus(1)
+
+BUGS
+====
+
+Report bugs by using https://bugs.taler.net/ or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/sync-config.1.rst b/manpages/sync-config.1.rst
new file mode 100644
index 00000000..c7dd9eab
--- /dev/null
+++ b/manpages/sync-config.1.rst
@@ -0,0 +1,101 @@
+sync-config(1)
+##############
+
+.. only:: html
+
+ Name
+ ====
+
+ **sync-config** - manipulate Sync configuration file
+
+Synopsis
+========
+
+**sync-config**
+[**-b** *backend* | **--supported-backend=**\ \ *backend*]
+[**-c** *filename* | **--config=**\ \ *filename*]
+[**-f** | **--filename**]
+[**-F** | **--full**]
+[**-h** | **--help**]
+[**-L** *loglevel* | **--loglevel=**\ \ *loglevel*]
+[**-l** *filename* | **--logfile=**\ ‌\ *filename*]
+[**-o** *option* | **--option=**\ \ *option*]
+[**-r** | **--rewrite**]
+[**-S** | **--list-sections**]
+[**-s** *section* | **--section=**\ \ *section*]
+[**-V** *value* | **--value=**\ \ *value*]
+[**-v** | **--version**]
+
+
+Description
+===========
+
+**sync-config** can be used to read or modify Sync configuration files.
+
+**-b** *BACKEND* \| **--supported-backend=**\ \ *BACKEND*
+ Tests whether the specified *BACKEND* is supported by the current installation.
+ The backend must match the name of a plugin, i.e. "namestore_postgres" for
+ the PostgreSQL database backend of the "NAMESTORE" service. If *BACKEND* is
+ supported, sync-config will return a status code of 0 (success), otherwise
+ 77 (unsupported). When this option is specified, no other options may be
+ specified. Specifying this option together with other options will cause
+ sync-config to return a status code of 1 (error).
+
+**-c** *FILENAME* \| **--config=**\ \ *FILENAME*
+ Use the configuration file *FILENAME*.
+
+**-f** \| **--filename**
+ Try to perform expansions as if the option values represent filenames (will
+ also be applied even if the option is not really a filename).
+
+**-F** \| **--full**
+ Write the full configuration file, not just the differences to the defaults.
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-L** *LOGLEVEL* \| **--loglevel=**\ \ *LOGLEVEL*
+ Use *LOGLEVEL* for logging.
+ Valid values are ``DEBUG``, ``INFO``, ``WARNING``, and ``ERROR``.
+
+**-l** *FILENAME* \| **--logfile=**\ ‌\ *FILENAME*
+ Send logging output to *FILENAME*.
+
+**-o** *OPTION* \| **--option=**\ \ *OPTION*
+ Which configuration option should be accessed or edited. Required to set a
+ value. If not given, all values of a given section will be printed in the
+ format "OPTION = VALUE".
+
+**-r** \| **--rewrite**
+ Write the configuration file even if nothing changed. Will remove all comments!
+
+**-S** \| **--list-sections**
+ List available configuration sections for use with ``--section``.
+
+**-s** *SECTION* \| **--section=**\ \ *SECTION*
+ Which configuration section should be accessed or edited.
+ Required option.
+
+**-V** *VALUE* \| **--value=**\ \ *VALUE*
+ Configuration value to store in the given section under the given option.
+ Must only be given together with ``-s`` and ``-o`` options.
+
+ Note:
+ Changing the configuration file with ``-V`` will remove comments
+ and may reorder sections and remove ``@INLINE@`` directives.
+
+**-v** \| **--version**
+ Print GNU Taler version number.
+
+
+See Also
+========
+
+sync-dbinit(1), sync-httpd(1), sync.conf(5).
+
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/sync-dbconfig.1.rst b/manpages/sync-dbconfig.1.rst
new file mode 100644
index 00000000..bafc5df6
--- /dev/null
+++ b/manpages/sync-dbconfig.1.rst
@@ -0,0 +1,61 @@
+sync-dbconfig(1)
+################
+
+.. only:: html
+
+ Name
+ ====
+
+ **sync-dbconfig** - configure sync database
+
+
+Synopsis
+========
+
+**sync-dbconfig**
+[**-c** *FILENAME*]
+[**-h**]
+[**-n** *NAME*]
+[**-r**]
+[**-s**]
+[**-u** *USER*]
+
+Description
+===========
+
+**sync-dbconfig** is a simple shell script that configures
+a Postgresql database for use by ``sync-httpd``.
+
+Its options are as follows:
+
+**-c** *FILENAME*
+ Write the database configuration to FILENAME. The tool
+ will append the required ``CONFIG`` option for the
+ Postgresql access to the respective file.
+
+**-h**
+ Print short help on options.
+
+**-n** *DBNAME*
+ Use DBNAME for the name of the created database.
+
+**-r**
+ Reset any existing database. Looses all existing data. DANGEROUS.
+
+**-s**
+ Skip database initialization. Useful if you want to run
+ ``sync-dbinit`` manually.
+
+**-u** *USER*
+ Specifies the (main) sync user that will access the database.
+
+See Also
+========
+
+sync-dbinit(1), sync.conf(5).
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/sync-dbinit.1.rst b/manpages/sync-dbinit.1.rst
new file mode 100644
index 00000000..63cc7ce7
--- /dev/null
+++ b/manpages/sync-dbinit.1.rst
@@ -0,0 +1,65 @@
+sync-dbinit(1)
+##############
+
+.. only:: html
+
+ Name
+ ====
+
+ **sync-dbinit** - initialize the Sync database
+
+
+Synopsis
+========
+
+**sync-dbinit**
+[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
+[**-g** | **--garbagecollect**]
+[**-h** | **--help**]
+[**-L** *LOGLEVEL* | **--log=**\ \ *LOGLEVEL*]
+[**-l** *FILENAME* | **--logfile=**\ \ *FILENAME*]
+[**-r** | **--reset**]
+[**-v** | **--version**]
+
+
+Description
+===========
+
+**sync-dbinit** is a command-line tool to initialize the Sync database.
+
+Its options are as follows:
+
+**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
+ Use the configuration and other resources for the Sync commands
+ to operate from *FILENAME*.
+
+**-g** \| **--garbagecollect**
+ Remove state data from database.
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-L** *LOGLEVEL* \| **--log=**\ \ *LOGLEVEL*
+ Configure logging to use *LOGLEVEL*.
+
+**-l** *FILENAME* \| **--logfile=**\ \ *FILENAME*
+ Configure logging to write logs to *FILENAME*.
+
+**-r** \| **--reset**
+ Reset database. (**DANGEROUS**: All existing data is lost!)
+
+**-v** \| **–version**
+ Print version information.
+
+
+See Also
+========
+
+sync-config(1), sync-httpd(1), sync.conf(5).
+
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/sync-httpd.1.rst b/manpages/sync-httpd.1.rst
new file mode 100644
index 00000000..c09ccb14
--- /dev/null
+++ b/manpages/sync-httpd.1.rst
@@ -0,0 +1,78 @@
+sync-httpd(1)
+#############
+
+.. only:: html
+
+ Name
+ ====
+
+ **sync-httpd** - provide the Sync HTTP interface
+
+
+Synopsis
+========
+
+**sync-httpd**
+[**-A** *USERNAME:PASSWORD* | **--auth=**\ \ *USERNAME:PASSWORD*]
+[**-C** | **--connection-close**]
+[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
+[**-h** | **--help**]
+[**-k** *KEYFILE* | **--key=**\ \ *KEYFILE*]
+[**-L** *LOGLEVEL* | **--log=**\ \ *LOGLEVEL*]
+[**-l** *FILENAME* | **--logfile=**\ \ *FILENAME*]
+[**-p** *KEYFILEPASSPHRASE* | **--pass=**\ \ *KEYFILEPASSPHRASE*]
+[**-t** *CERTTYPE* | **--type=**\ \ *CERTTYPE*]
+[**-v** | **--version**]
+
+
+Description
+===========
+
+**sync-httpd** is a command-line tool to provide the Sync HTTP interface.
+
+Its options are as follows:
+
+**-A** *USERNAME:PASSWORD* \| **--auth=**\ \ *USERNAME:PASSWORD*
+ Use the given *USERNAME* and *PASSWORD* for client authentication.
+
+**-C** \| **--connection-close**
+ Force HTTP connections to be closed after each request.
+
+**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
+ Use the configuration and other resources for the Sync commands
+ to operate from *FILENAME*.
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-k** *KEYFILE* \| **--key=**\ \ *KEYFILE*
+ Consult *KEYFILE* for the private TLS key for TLS client authentication.
+
+**-L** *LOGLEVEL* \| **--log=**\ \ *LOGLEVEL*
+ Configure logging to use *LOGLEVEL*.
+
+**-l** *FILENAME* \| **--logfile=**\ \ *FILENAME*
+ Configure logging to write logs to *FILENAME*.
+
+**-p** *KEYFILEPASSPHRASE* \| **--pass=**\ \ *KEYFILEPASSPHRASE*
+ Use *KEYFILEPASSPHRASE* to decrypt the TLS client private key file.
+
+**-t** *CERTTYPE* \| **--type=**\ \ *CERTTYPE*
+ Use *CERTTYPE* as the type of the TLS client certificate.
+ If unspecified, defaults to PEM.
+
+**-v** \| **–version**
+ Print version information.
+
+
+See Also
+========
+
+sync-config(1), sync-dbinit(1), sync.conf(5).
+
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/sync.conf.5.rst b/manpages/sync.conf.5.rst
new file mode 100644
index 00000000..f2a0e6a9
--- /dev/null
+++ b/manpages/sync.conf.5.rst
@@ -0,0 +1,92 @@
+sync.conf(5)
+############
+
+.. only:: html
+
+ Name
+ ====
+
+ **sync.conf** - Sync configuration file
+
+
+Description
+===========
+
+.. include:: ../frags/common-conf-syntax.rst
+
+Files containing default values for many of the options described below
+are installed under ``$PREFIX/share/sync/config.d/``.
+The configuration file given with **-c** to Sync binaries
+overrides these defaults.
+
+A configuration file may include another, by using the ``@INLINE@`` directive,
+for example, in ``main.conf``, you could write ``@INLINE@ sub.conf`` to
+include the entirety of ``sub.conf`` at that point in ``main.conf``.
+
+Be extra careful when using ``sync-config -V VALUE`` to change configuration
+values: it will destroy all uses of ``@INLINE@`` and furthermore remove all
+comments from the configuration file!
+
+
+GLOBAL OPTIONS
+--------------
+
+The following options are from the “[sync]” section.
+This is normally the only section in a sync.conf file.
+
+SERVE
+ This can either be ``tcp`` or ``unix``.
+
+PORT
+ Port on which the HTTP server listens, e.g. 9967.
+ Only used if ``SERVE`` is ``tcp``.
+
+BIND_TO
+ Which IP address should we bind to? E.g. ``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``.
+
+UNIXPATH
+ Which unix domain path should we bind to?
+ Only used if ``SERVE`` is ``unix``.
+
+UNIXPATH_MODE = 660
+ What should be the file access permissions for ``UNIXPATH``?
+ Only used if ``SERVE`` is ``unix``.
+
+DB
+ Plugin to use for the database, e.g. “postgres”.
+
+ANNUAL_FEE
+ Annual fee for an account.
+ This is in the usual amount syntax, e.g. ``TESTKUDOS:0.1``.
+
+INSURANCE
+ Insurance provided against loss, e.g. ``TESTKUDOS:0.0``.
+
+UPLOAD_LIMIT_MB
+ Upload limit per backup, in megabytes, e.g. ``16``.
+
+FULFILLMENT_URL
+ Fulfillment URL of the SYNC service itself.
+
+PAYMENT_BACKEND_URL
+ Base URL of our payment backend.
+
+API_KEY
+ API key to pass when accessing the merchant backend.
+ This is a secret value.
+
+
+SEE ALSO
+========
+
+sync-dbinit(1), sync-httpd(1), sync-config(1).
+
+
+BUGS
+====
+
+Report bugs by using https://bugs.taler.net/ or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-aggregator-benchmark.1.rst b/manpages/taler-aggregator-benchmark.1.rst
new file mode 100644
index 00000000..7047f6f7
--- /dev/null
+++ b/manpages/taler-aggregator-benchmark.1.rst
@@ -0,0 +1,72 @@
+taler-aggregator-benchmark(1)
+#############################
+
+
+.. only:: html
+
+ Name
+ ====
+
+ **taler-aggregator-benchmark** - setup database to measure aggregator performance
+
+
+Synopsis
+========
+
+**taler-aggregator-benchmark**
+[**-c** *CONFIG_FILENAME* | **--config=**\ ‌\ *CONFIG_FILENAME*]
+[**-d** *DN* | **--deposits=**\ \ *DN*]
+[**-h** | **--help**]
+[**-L** *LOGLEVEL* | **--log-level=**\ ‌\ *LOGLEVEL*]
+[**-l** *FILENAME* | **--logfile=**\ ‌\ *FILENAME*]
+[**-m** *DM* | **--merchants=**\ ‌\ *DM*]
+[**-r** *RATE* | **--refunds=**\ \ *RATE*]
+[**-v** | **--version**]
+
+Description
+===========
+
+**taler-aggregator-benchmark** is a command-line tool to fill an exchange
+database with records suitable for benchmarking the
+**taler-exchange-aggregator**. The **taler-aggregator-benchmark** tool does
+not run the actual workload for the benchmark (which usually consists of
+starting multiple **taler-exchange-aggregator** processes) and instead only
+prepares the database with synthetic work.
+
+**-c** *CONFIG_FILENAME* \| **--config=**\ ‌\ *CONFIG_FILENAME*
+ (Mandatory) Use CONFIG_FILENAME as the name for the configuration file.
+
+**-d** *DN* \| **--deposits=**\ ‌\ *DN*
+ How many deposits should be instantiated *per merchant*.
+ Defaults to 1.
+
+**-h** \| **--help**
+ Prints a compiled-in help text.
+
+**-L** *LOGLEVEL* \| **--log-level=**\ ‌\ *LOGLEVEL*
+ Specifies the log level to use. Accepted values are: ``DEBUG``, ``INFO``,
+ ``WARNING``, ``ERROR``.
+
+**-l** *FILENAME* \| **--logfile=**\ ‌\ *FILENAME*
+ Send logging output to *FILENAME*.
+
+**-m** *DM* \| **--merchants=**\ ‌\ *DM*
+ How many different merchants should we create. Defaults to 1.
+
+**-r** *RATE* \| **--refunds=**\ \ *RATE*
+ Probability of a deposit having a refund (as an integer between 0-100).
+
+**-v** \| **--version**
+ Print version information.
+
+See Also
+========
+
+taler-exchange-dbinit(1), taler-merchant-benchmark(1),
+taler-exchange-aggregator(1), taler-unified-setup(1), taler.conf(5)
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net/ or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-auditor-dbconfig.1.rst b/manpages/taler-auditor-dbconfig.1.rst
new file mode 100644
index 00000000..b16fd76d
--- /dev/null
+++ b/manpages/taler-auditor-dbconfig.1.rst
@@ -0,0 +1,61 @@
+taler-auditor-dbconfig(1)
+#########################
+
+.. only:: html
+
+ Name
+ ====
+
+ **taler-auditor-dbconfig** - configure Taler auditor database
+
+
+Synopsis
+========
+
+**taler-auditor-dbconfig**
+[**-c** *FILENAME*]
+[**-h**]
+[**-n** *NAME*]
+[**-r**]
+[**-s**]
+[**-u** *USER*]
+
+Description
+===========
+
+**taler-auditor-dbconfig** is a simple shell script that configures
+a Postgresql database for use by the GNU Taler auditor.
+
+Its options are as follows:
+
+**-c** *FILENAME*
+ Write the database configuration to FILENAME. The tool
+ will append the required ``CONFIG`` option for the
+ Postgresql access to the respective file.
+
+**-h**
+ Print short help on options.
+
+**-n** *DBNAME*
+ Use DBNAME for the name of the created database.
+
+**-r**
+ Reset any existing database. Looses all existing data. DANGEROUS.
+
+**-s**
+ Skip database initialization. Useful if you want to run
+ ``taler-auditor-dbinit`` manually.
+
+**-u** *USER*
+ Specifies the (main) auditor user that will access the database.
+
+See Also
+========
+
+taler-auditor-dbinit(1), taler.conf(5).
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-auditor-offline.1.rst b/manpages/taler-auditor-offline.1.rst
index 58a99066..24785082 100644
--- a/manpages/taler-auditor-offline.1.rst
+++ b/manpages/taler-auditor-offline.1.rst
@@ -24,7 +24,7 @@ Description
===========
**taler-auditor-offline** is a command-line tool to be used by an auditor to
-sign that he is aware of certain keys being used by a exchange. Using this
+sign that he is aware of certain keys being used by an exchange. Using this
signature, the auditor affirms that he will verify that the exchange is
properly accounting for coins of those denominations. The tool takes a list
of subcommands as arguments which are then processed sequentially.
diff --git a/manpages/taler-auditor.1.rst b/manpages/taler-auditor.1.rst
index 62cbf69e..9a5fc52b 100644
--- a/manpages/taler-auditor.1.rst
+++ b/manpages/taler-auditor.1.rst
@@ -15,6 +15,7 @@ Synopsis
[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
[**-h** | **--help**]
[**-i**_|_**--internal**]
+[**-I**_|_**--ignore-not-found**]
[**-L** *LOGLEVEL* | **--loglevel=**\ ‌\ *LOGLEVEL*]
[**-l** *FILENAME* | **--logfile=**\ ‌\ *FILENAME*]
[**-m** *MASTER_KEY* | **--exchange-key=**\ ‌\ *MASTER_KEY*]
@@ -46,6 +47,10 @@ matches the exchange’s database. Its options are as follows.
Run additional checks that can only performed on the exchange-internal
database and not the "safe" replicated database at the auditor.
+**-I** \| **--ignore-not-found**
+ Do not fail if the bank says that the exchange bank account does not (yet) exist.
+ Keep trying.
+
**-L** *LOGLEVEL* \| **--loglevel=**\ ‌\ *LOGLEVEL*
Specifies the log level to use. Accepted values are: ``DEBUG``, ``INFO``,
``WARNING``, ``ERROR``.
diff --git a/manpages/taler-bank-benchmark.1.rst b/manpages/taler-bank-benchmark.1.rst
index 52078fa9..be7aceb1 100644
--- a/manpages/taler-bank-benchmark.1.rst
+++ b/manpages/taler-bank-benchmark.1.rst
@@ -13,18 +13,16 @@ Synopsis
**taler-bank-benchmark**
[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
+[**-f** | **--fakebank**]
[**-h** | **--help**]
-[**-K** | **--linger**]
[**-L** *LOGLEVEL* | **--loglevel=**\ ‌\ *LOGLEVEL*]
[**-l** *FILENAME* | **--logfile=**\ ‌\ *FILENAME*]
-[**-m** *MODE* | **--mode=**\ \ *MODE*]
[**-p** *NPROCS* | **--worker-parallelism=**\ \ *NPROCS*]
-[**-P** *NTHREADS* | **--service-parallelism=**\ \ *NTHREADS*]
[**-r** *NRESERVES* | **--reserves=**\ \ *NRESERVES*]
-[**-s** *HISTSIZE* | **--size=**\ \ *HISTSIZE*]
+[**-u** *SECTION* | **--exchange-account-section=**\ \ *SECTION*]
[**-V** | **--verbose**]
[**-v** | **--version**]
-[**-w** | **--wirewatch**]
+[**-w**_*NPROC* | **--wirewatch=**\ \ *NPROC*]
Description
@@ -39,12 +37,12 @@ The options for **taler-bank-benchmark** are:
Use the configuration and other resources for the merchant to operate
from *FILENAME*.
+**-f** \| **--fakebank**
+ Expect to be run against a fakebank (instead of against libeufin)
+
**-h** \| **--help**
Print short help on options.
-**-K** \| **--linger**
- Linger around until key press.
-
**-L** *LOGLEVEL* \| **--loglevel=**\ ‌\ *LOGLEVEL*
Specifies the log level to use. Accepted values are: ``DEBUG``, ``INFO``,
``WARNING``, ``ERROR``.
@@ -56,17 +54,14 @@ The options for **taler-bank-benchmark** are:
Run as ``bank``, ``client`` or ``both``.
If unspecified, *MODE* defaults to ``both``.
-**-P** *NTHREADS** \| **--service-parallelism=**\ \ *NTHREADS*
- Run with *NTHREADS* service threads.
-
**-p** *NPROCS* \| **--worker-parallelism=**\ \ *NPROCS*
Run with *NPROCS* client processes.
**-r** *NRESERVES* \| **--reserves=**\ \ *NRESERVES*
Create *NRESERVES* reserves per client.
-**-s** *HISTSIZE* \| **--size=**\ \ *HISTSIZE*
- Configure the fakebank to keep in memory at most *HISTSIZE* history elements.
+**-u** *SECTION* \| **--exchange-account-section=**\ \ *SECTION*
+ Use *SECTION* as the name of the configuration section which specifies the exchange bank account.
**-V** \| **--verbose**
Display more output than usual.
@@ -74,8 +69,9 @@ The options for **taler-bank-benchmark** are:
**-v** \| **--version**
Print version information.
-**-w** \| **--wirewatch**
- Run the ``taler-exchange-wirewatch`` tool.
+**-w** *NPROC* \| **--wirewatch=**\ \ *NPROC*
+ Run *NPROC* processes of the ``taler-exchange-wirewatch`` tool.
+
See Also
========
diff --git a/manpages/taler-config.1.rst b/manpages/taler-config.1.rst
index 103c95ef..abc10dd6 100644
--- a/manpages/taler-config.1.rst
+++ b/manpages/taler-config.1.rst
@@ -35,7 +35,7 @@ Description
**-b** *BACKEND* \| **--supported-backend=**\ \ *BACKEND*
Tests whether the specified *BACKEND* is supported by the current installation.
The backend must match the name of a plugin, i.e. "namestore_postgres" for
- the Postgres database backend of the "NAMESTORE" service. If *BACKEND* is
+ the PostgreSQL database backend of the "NAMESTORE" service. If *BACKEND* is
supported, taler-config will return a status code of 0 (success), otherwise
77 (unsupported). When this option is specified, no other options may be
specified. Specifying this option together with other options will cause
@@ -83,6 +83,7 @@ Description
Note:
Changing the configuration file with ``-V`` will remove comments
and may reorder sections and remove ``@INLINE@`` directives.
+ Using **-V** is thus dangerous! Use with extreme caution!
**-v** \| **--version**
Print GNU Taler version number.
diff --git a/manpages/taler-exchange-aggregator.1.rst b/manpages/taler-exchange-aggregator.1.rst
index 4a15c227..87a5cd74 100644
--- a/manpages/taler-exchange-aggregator.1.rst
+++ b/manpages/taler-exchange-aggregator.1.rst
@@ -19,6 +19,8 @@ Synopsis
[**-T** *USEC* | **--timetravel**\ \ *USEC*]
[**-t** | **--test**]
[**-v** | **--version**]
+[**-y**_|_**--kyc-off**]
+
Description
===========
@@ -56,6 +58,10 @@ The aggregator uses a special table to lock shards it is working on. If an aggre
**-v** \| **--version**
Print version information.
+**-y** \| **--kyc-off**
+ Run without KYC checks. Talk with your regulator before using this option.
+
+
See Also
========
diff --git a/manpages/taler-exchange-benchmark.1.rst b/manpages/taler-exchange-benchmark.1.rst
index bcbcb3c1..694a4b2d 100644
--- a/manpages/taler-exchange-benchmark.1.rst
+++ b/manpages/taler-exchange-benchmark.1.rst
@@ -18,25 +18,21 @@ Synopsis
[**-F** | **--reserves-first**]
[**-f** | **--fakebank**]
[**-h** | **--help**]
-[**-K** | **--linger**]
[**-L** *LOGLEVEL* | **--log-level=**\ ‌\ *LOGLEVEL*]
[**-l** *FILENAME* | **--logfile=**\ ‌\ *FILENAME*]
-[**-m** *MODE* | **--mode=**\ \ *MODE*]
[**-n** *HOWMANY_COINS* | **--coins-number=**\ ‌\ *HOWMANY_COINS*]
[**-p** *NPROCS* | **--parallelism=**\ \ *NPROCS*]
[**-R** *RATE* | **--refresh-rate=**\ \ *RATE*]
[**-r** *N* | **--reserves=**\ \ *N*]
+[**-u** *SECTION* | **--exchange-account-section=**\ \ *SECTION*]
[**-v** | **--version**]
Description
===========
**taler-exchange-benchmark** is a command-line tool to measure the time
-spent to serve withdrawals/deposits/refreshes. It usually needs a
-dedicate configuration file where all the services - the exchange and
-the (fake)bank - listen to URLs not subject to any reverse proxy, as say
-Nginx. Moreover, the benchmark runs on a “volatile” database, that means
-that table are always erased during a single benchmark run.
+spent to serve withdrawals/deposits/refreshes. Before running the benchmark,
+the GNU Taler services must already be running at the configured addresses.
**-c** *CONFIG_FILENAME* \| **--config=**\ ‌\ *CONFIG_FILENAME*
(Mandatory) Use CONFIG_FILENAME.
@@ -45,18 +41,11 @@ that table are always erased during a single benchmark run.
Create all reserves first, before starting normal operations.
**-f** \| **--fakebank**
- Launch a fakebank instead of the Python bank. Only meaningful if the
- mode is to launch more than just a client. Note that using the
- fakebank will cause the benchmark application to reset all databases
- as the fakebank is stateless and thus previous database state would
- inherently cause trouble.
+ Expect to interact with a fakebank instead of libeufin.
**-h** \| **--help**
Prints a compiled-in help text.
-**-K** \| **--linger**
- Linger around until keypress after the benchmark is done.
-
**-L** *LOGLEVEL* \| **--log-level=**\ ‌\ *LOGLEVEL*
Specifies the log level to use. Accepted values are: ``DEBUG``, ``INFO``,
``WARNING``, ``ERROR``.
@@ -64,9 +53,6 @@ that table are always erased during a single benchmark run.
**-l** *FILENAME* \| **--logfile=**\ ‌\ *FILENAME*
Send logging output to *FILENAME*.
-**-m** *MODE* \| **--mode=**\ \ *MODE*
- Mode of operation. Accepted values are: ``exchange``, ``clients``, ``both``.
-
**-n** *HOWMANY_COINS* \| **--coins-number=**\ ‌\ *HOWMANY_COINS*
Defaults to 1. Specifies how many coins this benchmark should
withdraw and spend. After being spent, each coin will be refreshed
@@ -81,6 +67,10 @@ that table are always erased during a single benchmark run.
**-r** *N* \| **--reserves=**\ \ *N*
Create *N* reserves per client.
+**-u** *SECTION* \| **--exchange-account-section=**\ \ *SECTION*
+ Which configuration section should be used for the bank account
+ of the exchange.
+
**-v** \| **--version**
Print version information.
@@ -88,7 +78,7 @@ See Also
========
taler-exchange-dbinit(1), taler-exchange-offline(1), taler-merchant-benchmark(1),
-taler-exchange-httpd(1), taler.conf(5)
+taler-exchange-httpd(1), taler-unified-setup(1), taler.conf(5)
Bugs
====
diff --git a/manpages/taler-exchange-dbconfig.1.rst b/manpages/taler-exchange-dbconfig.1.rst
new file mode 100644
index 00000000..38cb1cba
--- /dev/null
+++ b/manpages/taler-exchange-dbconfig.1.rst
@@ -0,0 +1,61 @@
+taler-exchange-dbconfig(1)
+##########################
+
+.. only:: html
+
+ Name
+ ====
+
+ **taler-exchange-dbconfig** - configure Taler exchange database
+
+
+Synopsis
+========
+
+**taler-exchange-dbconfig**
+[**-c** *FILENAME*]
+[**-h**]
+[**-n** *NAME*]
+[**-r**]
+[**-s**]
+[**-u** *USER*]
+
+Description
+===========
+
+**taler-exchange-dbconfig** is a simple shell script that configures
+a Postgresql database for use by the GNU Taler exchange.
+
+Its options are as follows:
+
+**-c** *FILENAME*
+ Write the database configuration to FILENAME. The tool
+ will append the required ``CONFIG`` option for the
+ Postgresql access to the respective file.
+
+**-h**
+ Print short help on options.
+
+**-n** *DBNAME*
+ Use DBNAME for the name of the created database.
+
+**-r**
+ Reset any existing database. Looses all existing data. DANGEROUS.
+
+**-s**
+ Skip database initialization. Useful if you want to run
+ ``taler-exchange-dbinit`` manually.
+
+**-u** *USER*
+ Specifies the (main) exchange user that will access the database.
+
+See Also
+========
+
+taler-exchange-dbinit(1), taler.conf(5).
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-exchange-dbinit.1.rst b/manpages/taler-exchange-dbinit.1.rst
index 0ee83543..cbbc494c 100644
--- a/manpages/taler-exchange-dbinit.1.rst
+++ b/manpages/taler-exchange-dbinit.1.rst
@@ -13,6 +13,7 @@ Synopsis
========
**taler-exchange-dbinit**
+[**-a** | **--inject-auditor**]
[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
[**-g** | **--gc**]
[**-h** | **--help**]
@@ -31,6 +32,9 @@ Taler exchange to operate.
Its options are as follows:
+**-a** \| **--inject-auditor**
+ Installs triggers to notify real-time auditors of relevant changes to the database state.
+
**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
Use the configuration and other resources for the exchange to operate
from *FILENAME*.
diff --git a/manpages/taler-exchange-drain.1.rst b/manpages/taler-exchange-drain.1.rst
new file mode 100644
index 00000000..ade7c00e
--- /dev/null
+++ b/manpages/taler-exchange-drain.1.rst
@@ -0,0 +1,56 @@
+taler-exchange-drain(1)
+#########################
+
+.. only:: html
+
+ Name
+ ====
+
+ **taler-exchange-drain** - drain profits from exchange escrow account
+
+Synopsis
+========
+
+**taler-exchange-drain**
+[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
+[**-h** | **--help**]
+[**-L** *LOGLEVEL* | **--loglevel=**\ ‌\ *LOGLEVEL*]
+[**-l** *FILENAME* | **--logfile=**\ ‌\ *FILENAME*]
+[**-v** | **--version**]
+
+Description
+===========
+
+**taler-exchange-drain** is used to trigger a wire transfer from the exchange's escrow account to a normal (non-escrowed) bank account of the exchange. The entire drain process is necessary to ensure that the auditor is aware of the
+balance changes arising from an exchange making profits from fees.
+
+To use it, you must first create an upload a 'drain' command using **taler-exchange-offline**. Afterwards this command should be run to actually queue the drain. The actual drain will then be executed by **taler-exchange-transfer**.
+
+
+**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
+ Use the configuration and other resources for the exchange to operate
+ from *FILENAME*.
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-L** *LOGLEVEL* \| **--loglevel=**\ ‌\ *LOGLEVEL*
+ Specifies the log level to use. Accepted values are: ``DEBUG``, ``INFO``,
+ ``WARNING``, ``ERROR``.
+
+**-l** *FILENAME* \| **--logfile=**\ ‌\ *FILENAME*
+ Send logging output to *FILENAME*.
+
+**-v** \| **--version**
+ Print version information.
+
+See Also
+========
+
+taler-exchange-transfer(1), taler-exchange-offline(1), taler.conf(5).
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net/ or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-exchange-expire.1.rst b/manpages/taler-exchange-expire.1.rst
new file mode 100644
index 00000000..24540ec4
--- /dev/null
+++ b/manpages/taler-exchange-expire.1.rst
@@ -0,0 +1,66 @@
+taler-exchange-expire(1)
+#########################
+
+.. only:: html
+
+ Name
+ ====
+
+ **taler-exchange-expire** - refund expired purses
+
+Synopsis
+========
+
+**taler-exchange-expire**
+[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
+[**-h** | **--help**]
+[**-L** *LOGLEVEL* | **--loglevel=**\ ‌\ *LOGLEVEL*]
+[**-l** *FILENAME* | **--logfile=**\ ‌\ *FILENAME*]
+[**-T** *USEC* | **--timetravel=**\ \ *USEC*]
+[**-t** | **--test**]
+[**-v** | **--version**]
+
+Description
+===========
+
+**taler-exchange-expire** is a command-line tool to run refund
+money in purses that were not merged before their expiration time.
+This allows the wallet to recover the funds deposited into the
+purse using a refresh operation.
+
+
+**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
+ Use the configuration and other resources for the exchange to operate
+ from *FILENAME*.
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-L** *LOGLEVEL* \| **--loglevel=**\ ‌\ *LOGLEVEL*
+ Specifies the log level to use. Accepted values are: ``DEBUG``, ``INFO``,
+ ``WARNING``, ``ERROR``.
+
+**-l** *FILENAME* \| **--logfile=**\ ‌\ *FILENAME*
+ Send logging output to *FILENAME*.
+
+**-T** *USEC* \| **--timetravel=**\ \ *USEC*
+ Modify the system time by *USEC* microseconds.
+ *USEC* may be prefixed with ``+`` or ``-`` (e.g. ``-T +300``).
+ This option is intended for debugging/testing only.
+
+**-t** \| **--test**
+ Run in test mode and exit when idle.
+
+**-v** \| **--version**
+ Print version information.
+
+See Also
+========
+
+taler-exchange-router(1), taler-exchange-httpd(1), taler.conf(5).
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net/ or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-exchange-httpd.1.rst b/manpages/taler-exchange-httpd.1.rst
index 0050aeeb..4c6d984b 100644
--- a/manpages/taler-exchange-httpd.1.rst
+++ b/manpages/taler-exchange-httpd.1.rst
@@ -20,6 +20,7 @@ Synopsis
[**-L** *LOGLEVEL* | **--loglevel=**\ ‌\ *LOGLEVEL*]
[**-l** *FILENAME* | **--logfile=**\ ‌\ *FILENAME*]
[**-n** *N* | **--num-threads=**\ \ *N*]
+[**-r**|**--allow-reuse-address**]
[**-T** *USEC* | **--timetravel=**\ \ *USEC*]
[**-t** *SECONDS* | **--timeout=**\ ‌\ *SECONDS*]
[**-v** | **--version**]
@@ -75,8 +76,10 @@ Its options are as follows:
**-l** *FILENAME* \| **--logfile=**\ ‌\ *FILENAME*
Send logging output to *FILENAME*.
-**-n** *N* \| **--num-threads=**\ \ *N*
- Use *N* threads in the thread pool.
+**-r** \| **--allow-reuse-address**
+ Allow the exchange to re-use the listen port even if another service
+ is already using it. Useful if multiple processes are used to increase
+ processing capacity.
**-T** *USEC* \| **--timetravel=**\ \ *USEC*
Modify the system time by *USEC* microseconds.
diff --git a/manpages/taler-exchange-kyc-aml-pep-trigger.1.rst b/manpages/taler-exchange-kyc-aml-pep-trigger.1.rst
new file mode 100644
index 00000000..566fdcab
--- /dev/null
+++ b/manpages/taler-exchange-kyc-aml-pep-trigger.1.rst
@@ -0,0 +1,35 @@
+taler-exchange-kyc-aml-pep-trigger(1)
+#####################################
+
+.. only:: html
+
+ Name
+ ====
+
+ **taler-exchange-kyc-aml-pep-trigger** - helper script to trigger AML if KYC attributes indicate a politically exposed person
+
+Synopsis
+========
+
+**taler-exchange-kyc-aml-pep-trigger**
+
+
+Description
+===========
+
+**taler-exchange-kyc-aml-pep-trigger** is a trivial shell script to illustrate how to trigger an AML process when the KYC process sets the "PEP" flag in the attribute data.
+
+The script is mostly an example (or starting point) for
+writing programs for the KYC_AML_TRIGGER option of the
+exchange.
+
+See Also
+========
+
+taler.conf(5)
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-exchange-kyc-tester.1.rst b/manpages/taler-exchange-kyc-tester.1.rst
new file mode 100644
index 00000000..6bfad3b2
--- /dev/null
+++ b/manpages/taler-exchange-kyc-tester.1.rst
@@ -0,0 +1,93 @@
+taler-exchange-kyc-tester(1)
+############################
+
+.. only:: html
+
+ Name
+ ====
+
+ **taler-exchange-kyc-tester** - tool to test interaction with KYC provider
+
+Synopsis
+========
+
+**taler-exchange-kyc-tester**
+[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
+[**-h** | **--help**]
+[**-L** *LOGLEVEL* | **--loglevel=**\ ‌\ *LOGLEVEL*]
+[**-l** *FILENAME* | **--logfile=**\ ‌\ *FILENAME*]
+[**-i** *SECTION_NAME* | **--initiate=**\ ‌\ *SECTION_NAME*]
+[**-u** *ID* | **--user=**\ ‌\ *ID*]
+[**-U** *ID* | **--legitimization=**\ ‌\ *ID*]
+[**-P** | **--print-payto-hash**]
+[**-p** *HASH* | **--payto-hash=**\ ‌\ *HASH*]
+[**-r** *NUMBER* | **--rowid=**\ ‌\ *NUMBER*]
+[**-v** | **--version**]
+[**-w** | **--run-webservice**]
+
+
+Description
+===========
+
+**taler-exchange-kyc-tester** is used to test the interaction between a Taler exchange and a KYC service. The tool can be used to manually trigger the various steps of a KYC process and to observe the interaction with the respective KYC service. It is supposted to help test the configuration of the integration, and *not* required at all during production.
+
+To use it, you must first provide a configuration file with at least one KYC service configured. Some other exchange-specific options, like the PORT for the HTTP service and the BASE_URL under which the Taler exchange will run are also required. You should be able to use exactly the same configuration file that one would usually give to a Taler exchange. Starting with this, the tool allows the simulation of a KYC process. Note that it will not write any information to the database.
+
+Begin with a first invocation of taler-exchange-kyc-tester using the options **-i** for an individual or business and use **-R** to specify a list of checks required from the process. The output will be an URL to visit with the browser, as well as **-p**, **-u**, **-U** options to use in future invocations of the tool.
+
+Next, run taler-exchange-kyc-tester again, but this time using **-w** (to run the Webserver) and using the **-u** and **-U** options output by the previous call, as well as the **-p** option with the payto hash. Then visit the Web site from the link output by the previous invocation and "pass" (or "fail") the KYC check.
+
+
+**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
+ Use the configuration and other resources for the exchange to operate
+ from *FILENAME*.
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-L** *LOGLEVEL* \| **--loglevel=**\ ‌\ *LOGLEVEL*
+ Specifies the log level to use. Accepted values are: ``DEBUG``, ``INFO``,
+ ``WARNING``, ``ERROR``.
+
+**-l** *FILENAME* \| **--logfile=**\ ‌\ *FILENAME*
+ Send logging output to *FILENAME*.
+
+**-i** *USERTYPE* \| **--initiate=**\ ‌\ *USERTYPE*
+ Specifies the type of user for which we are starting a fresh KYC process. USERTYPE must be either "individual" or "business".
+
+**-u** *ID* \| **--user=**\ ‌\ *ID*
+ Run the process with ID for the user identifier at the KYC provider. Not useful in conjunction with **-i** and **-R** as that option will override whatever value is provided here.
+
+**-U** *ID* \| **--legitimization=**\ ‌\ *ID*
+ Run the process with ID for the legitimization process identifier at the KYC provider. Not useful in conjunction with **-R** / **-i** as that option will override whatever value is provided here.
+
+**-p** *HASH* \| **--payto-hash=**\ ‌\ *HASH*
+ Run the process with HASH as the hash of the payto://-URI that identifies the account or wallet triggering the KYC requirement. If not given, a fresh random value is used. Rarely useful.
+
+**-P** \| **--print-payto-hash**
+ Print the HASH of the payto://-URI used for the KYC simulation this time. Useful if the hash is needed for a subsequent use in conjunction with **-p**.
+
+**-r** *NUMBER* \| **--rowid=**\ ‌\ *NUMBER*
+ Run the process with NUMBER as the database row for the legitimization operation. Rarely useful, except maybe for debugging. Defaults to 42.
+
+**-R** *CHECKS* \| **--requirements=**\ ‌\ *CHECKS*
+ Start a fresh KYC process for the given list of CHECKS. CHECKS must be a space-separated list of checks that must be in the configuration under *PROVIDED_CHECKS* for some of the providers. The exchange will determine which provider to use for KYC based on the CHECKS given. The tool will output the HTTP URL where the user has to begin the KYC process to the command-line. This is usually the first thing to do when using this tool. Outputs the KYC-logic specific user and legitimization IDs, or NULL if not used by the KYC-logic at the initiation stage. You may want to use the **-P** option to also obtain the Payto-Hash for use with **p** later.
+
+
+**-v** \| **--version**
+ Print version information.
+
+**-w** \| **--run-webservice**
+ Run a simulated Taler exchange HTTP service on the configured port with the ``/kyc-proof/`` and ``/kyc-webhook/`` endpoints.
+
+
+See Also
+========
+
+taler-exchange-httpd(1), taler.conf(5).
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net/ or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-exchange-offline.1.rst b/manpages/taler-exchange-offline.1.rst
index 4641b416..bd8cd793 100644
--- a/manpages/taler-exchange-offline.1.rst
+++ b/manpages/taler-exchange-offline.1.rst
@@ -142,6 +142,47 @@ It outputs the signatures over *all* denomination and signing keys
present in the input, in a format suitable for the ``upload`` subcommand.
+extensions
+----------
+
+This subcommand is responsible for the management of available extensions in
+the exchange.
+
+It consumes the output of the ``download`` subcommand, either from ``stdin`` or
+directly.
+
+It provides the sub-subcommand ``extensions show`` to show the configuration
+for extensions and the ``extensions sign`` command to sign the current
+configuration of extensions, in a format suitable for the ``upload``
+subcommand.
+
+Note that an extension on the exchange will only become activated at runtime
+*after* the extension's configurations has been signed by the offline tool with
+the signing key and the signed configuration been uploaded to the exchange.
+
+drain
+-----
+
+This subcommand allows an exchange operator to transfer the
+profits made from transaction fees to a regular (non-escrowed) bank
+account. Using this command, draining profits from the
+escrow account can be done in such a way that the auditor
+is aware of the special transaction and does not flag the
+resulting balance as fundamentally problematic. Note that
+the drained amounts must still total up to less than the fees
+earned by the exchange.
+
+Arguments to the ``drain`` command are the amount to be drained (in the usual
+Taler amount format), the section of the exchange configuration specifying the
+account to be debited (this argument is currently ignored, and the account is
+purely derived from the wire method and the account being set for debiting),
+and finally the payto://-URI to wire the funds to.
+
+Note that to actually wire the funds, the exchange administrator must run
+**taler-exchange-drain** manually and confirm the operation after the
+``upload`` was completed.
+
+
revoke-denomination
-------------------
@@ -217,31 +258,73 @@ in a format suitable for the ``upload`` subcommand.
enable-account
--------------
-This subcommand
-informs an exchange that it should advertize a bank account as belonging to
-the exchange on its ``/wire`` endpoint. Note that this does *not* ensure that
-the exchange will use this bank account for incoming or outgoing wire
-transfers! For this, the **taler-exchange-transfer** and
+This subcommand informs an exchange that it should advertise a bank account as
+belonging to the exchange on its ``/keys`` endpoint. Note that this does
+*not* ensure that the exchange will use this bank account for incoming or
+outgoing wire transfers! For this, the **taler-exchange-transfer** and
**taler-exchange-wirewatch** tools must be configured. Furthermore, the bank
-account information advertized could theoretically differ from that which
+account information advertised could theoretically differ from that which
these tool actually use, for example if the public bank account is only a
front for the actual internal business accounts.
The ``payto://`` URI (RFC 8905) of the exchange's bank account must be given
as the first argument to the subcommand.
+Afterwards, optional arguments can be given:
+
+ * ``conversion-url`` $URL: specifies that using this bank account is subject
+ to currency conversion. $URL must be the address of a currency conversion
+ REST API that allows merchants and wallets to determine the current
+ conversion rate.
+
+ * ``display-hint`` $PRIORITY $LABEL: specifies that this bank account should
+ be shown to the user with the given numeric $PRIORITY (higher is earlier)
+ and with the given $LABEL. This is useful to ensure that if an exchange
+ has multiple bank accounts, we can show the user those that are most likely
+ useful first, and give them appropriately labeled hints for selecting other
+ accounts as well. A display hint is optional, if missing the priority is 0
+ and the wallet must pick some appropriate label itself somehow.
+
+ * ``credit-restriction`` $TYPE [$ARGS]: Specifies that there are
+ restrictions in place when crediting this bank account. Details depend on
+ the restriction $TYPE. This argument may be given multiple times, in which
+ case debitor accounts must satisfy all restrictions. Restriction types are
+ discussed below.
+
+ * ``debit-restriction`` $TYPE [$ARGS]: Specifies that there are restrictions
+ in place when receiving money from the exchange. Wallets and merchants
+ must check that their target bank account satisfies these restrictions
+ before sending deposit requests to the exchange. Details depend on the
+ restriction $TYPE. This argument may be given multiple times, in which
+ case debitor accounts must satisfy all restrictions. Restriction types are
+ discussed below.
+
+The following types of credit- and debit-restrictions are supported:
+
+ * ``deny``: A $TYPE of ``deny`` means that this bank account cannot be used
+ for the given operation. ``deny`` takes no further arguments.
+
+ * ``regex`` $EXPR $HINT $JSON: A $TYPE of ``regex`` means that the partner's
+ bank account ``payto``-URI representation must follow a certain regular
+ expression given in $EXPR where the syntax follows posix-egrep, but
+ without support for character classes, GNU extensions, back-references or
+ intervals. See
+ `Findutils Manual <https://www.gnu.org/software/findutils/manual/html_node/find_html/posix_002degrep-regular-expression-syntax.html>`_
+ for a description of the posix-egrep syntax. The $HINT must be a
+ human-readable description of the $EXPR. $JSON should be a JSON array
+ mapping IETF BCP 47 language tags to localized versions of $HINT.
+
The subcommand takes no inputs from ``stdin`` or other subcommands.
It outputs the signature affirming the addition of the wire account,
in a format suitable for the ``upload`` subcommand.
-
disable-account
---------------
This subcommand
informs an exchange that it should stop advertising a bank account as
-belonging to the exchange on its ``/wire`` endpoint.
+belonging to the exchange on its ``/keys`` endpoint.
The ``payto://`` URI (RFC 8905) of the exchange's (former) bank account must be
given as the first argument to the subcommand.
@@ -255,13 +338,13 @@ format suitable for the ``upload`` subcommand.
wire-fee
--------
-This subcommand informs an exchange about the desired wire fee (and closing fee)
-structure for particular wire method and a calendar year (!). The tool does not
+This subcommand informs an exchange about the desired wire fee structure (that is, wire, and closing fees)
+for particular wire method and a calendar year (!). The tool does not
permit changing wire fees during a calendar year. Also, once the wire fee has been
set for a calendar year, it cannot be changed.
The subcommand takes the year, wire-method (see RFC 8905, examples include
-``x-taler-bank`` or ``iban``), wire fee and closing fee as arguments.
+``x-taler-bank`` or ``iban``), wire fee, and closing fee as arguments.
Instead of a year, the string ``now`` can be given for the current year
(this is mostly useful for test cases). The wire-method should follow the
GANA registry as given in RFC 8905. The fees must be given in the usual
@@ -273,6 +356,26 @@ It outputs the signature affirming the wire fees, in a format suitable for the
``upload`` subcommand.
+global-fee
+----------
+
+This subcommand informs an exchange about the desired global fee structure and
+related global configuration options for a calendar year (!). The tool does
+not permit changing global fees during a calendar year. Also, once the global
+fee structure has been set for a calendar year, it cannot be changed.
+
+The subcommand takes the year, history fee, account fee, purse fee,
+purse timeout, history expiration and the (free) purse (per)
+account limit as arguments. Instead of a year, the string ``now`` can be
+given for the current year (this is mostly useful for test cases). The fees
+must be given in the usual Taler format of ``CURRENCY:NUMBER.FRACTION``.
+
+The subcommand takes no inputs from ``stdin`` or other subcommands.
+
+It outputs the signature affirming the global fees, in a format suitable for
+the ``upload`` subcommand.
+
+
enable-partner
--------------
@@ -304,6 +407,45 @@ The arguments provided must include:
(9) History fee charged when inquiring about non-recent account history.
+aml-enable
+----------
+
+Enable AML officer's account, granting them access to AML data and,
+if 'rw' is given, the power to make AML decisions.
+
+The arguments provided must include:
+
+ (1) AML staff member public key (in base32 encoding)
+ (2) AML staff member legal name
+ (3) 'ro' or 'rw' to set access to read-only or read-write
+
+
+aml-disable
+-----------
+
+Disable AML officer's account. Also updates the legal name.
+
+The arguments provided must include:
+
+ (1) AML staff member public key (in base32 encoding)
+ (2) AML staff member legal name
+
+
+add-partner
+-----------
+
+Add partner exchange for wad transfers. Enables P2P payments
+between users of these exchanges.
+
+The arguments provided must include:
+
+ (1) Master public key of the partner exchange.
+ (2) Base URL of the partner exchange API.
+ (3) Wad fee to charge.
+ (4) Wad transfer frequency.
+ (5) Year for which the above options are to be configured, 'now' for the current year.
+
+
upload
------
@@ -356,25 +498,58 @@ Upload signatures about future public keys (online)
Download, sign and upload, all in one (online)
----------------------------------------------
-Note that doing this is only recommended in non-production deployments.
+Note that doing this is only recommended in non-production deployments,
+as this requires putting the "offline" key onto a system that is actually
+online!
.. code-block:: console
- $ taler-exchange-offline download sign upload
+ $ taler-exchange-offline \
+ download \
+ sign \
+ upload
Here is a variant that shows the output of ``download``, but does not consume it,
so that ``sign`` can see it as input, as in the variant without ``show``.
.. code-block:: console
- $ taler-exchange-offline download show - sign upload
+ $ taler-exchange-offline \
+ download \
+ show - \
+ sign \
+ upload
+
Create signature to enable bank account (offline)
-------------------------------------------------
+The following command sets up an unrestricted simple exchange bank account
+without conversion:
+
.. code-block:: console
- $ taler-exchange-offline enable-account payto://iban/DE24242 > account.json
+ $ taler-exchange-offline \
+ enable-account payto://iban/DE24242?receiver-name=operator > account.json
+
+The following command would set up an exchange bank account with conversion
+and restrict it to only receive money from Switzerland and deny its use for
+debit operations:
+
+.. code-block:: shell-session
+
+ $ taler-exchange-offline \
+ enable-account payto://x-taler-bank/example.com/?receiver-name=name \
+ conversion-url http://conversion.exchange.com/ \
+ debit-restriction \
+ deny \
+ credit-restriction \
+ regex \
+ 'payto://iban/.*/CH.*?receiver-name=.*' \
+ 'Swiss only' \
+ '{ "de" : "nur Schweiz", \
+ "fr" : "Suisse uniquement" }'
+
Upload bank account signature (online)
--------------------------------------
@@ -387,9 +562,19 @@ Upload bank account signature (online)
Combine signing keys and enabling bank account (offline)
--------------------------------------------------------
+You can chain multiple commands into one invocation:
+
.. code-block:: console
- $ taler-exchange-offline sign enable-account payto://iban/DE24242 < keys.json > combo.json
+ $ taler-exchange-offline \
+ sign \
+ enable-account \
+ payto://iban/DE24242 < keys.json > combo.json
+
+Note that ``sign`` must be first as it consumes the ``keys.json``
+input. The resulting output combines the outputs of the ``sign``
+and ``enable-account`` subcommands.
+
Upload various signatures (online)
----------------------------------
@@ -401,11 +586,20 @@ Upload various signatures (online)
Create multiple revocation messages in one pass (offline)
---------------------------------------------------------
+You can freely combine almost all commands, including those for
+key revocation:
+
.. code-block:: console
- $ taler-exchange-offline revoke-denomination $DKH1 revoke-denomination $DKH2 > revoke.json
- $ taler-exchange-offline revoke-signkey $SK1 revoke-signkey $SK2 > revoke.json
- $ taler-exchange-offline revoke-signkey $SK revoke-denomkey $DKH > mix.json
+ $ taler-exchange-offline \
+ revoke-denomination $DKH1 \
+ revoke-denomination $DKH2 > revoke.json
+ $ taler-exchange-offline \
+ revoke-signkey $SK1 \
+ revoke-signkey $SK2 > revoke.json
+ $ taler-exchange-offline \
+ revoke-signkey $SK \
+ revoke-denomkey $DKH > mix.json
The outputs ("revoke.json", "mix.json") must be uploaded using the ``upload``
subcommand to the exchange to actually revoke the keys.
diff --git a/manpages/taler-exchange-router.1.rst b/manpages/taler-exchange-router.1.rst
new file mode 100644
index 00000000..e24d2d45
--- /dev/null
+++ b/manpages/taler-exchange-router.1.rst
@@ -0,0 +1,67 @@
+taler-exchange-router(1)
+#########################
+
+.. only:: html
+
+ Name
+ ====
+
+ **taler-exchange-router** - route purse payments to partner exchanges
+
+Synopsis
+========
+
+**taler-exchange-router**
+[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
+[**-h** | **--help**]
+[**-L** *LOGLEVEL* | **--loglevel=**\ ‌\ *LOGLEVEL*]
+[**-l** *FILENAME* | **--logfile=**\ ‌\ *FILENAME*]
+[**-T** *USEC* | **--timetravel=**\ \ *USEC*]
+[**-t** | **--test**]
+[**-v** | **--version**]
+
+Description
+===========
+
+**taler-exchange-router** is a NOT YET IMPLEMENTED command-line
+tool to route P2P payments to partner exchanges via wad transfers.
+This will be needed if wallet-to-wallet payments are made between
+wallets where the recipient has performed the KYC at a different
+exchange than the sender. This is currently not supported.
+
+
+**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
+ Use the configuration and other resources for the exchange to operate
+ from *FILENAME*.
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-L** *LOGLEVEL* \| **--loglevel=**\ ‌\ *LOGLEVEL*
+ Specifies the log level to use. Accepted values are: ``DEBUG``, ``INFO``,
+ ``WARNING``, ``ERROR``.
+
+**-l** *FILENAME* \| **--logfile=**\ ‌\ *FILENAME*
+ Send logging output to *FILENAME*.
+
+**-T** *USEC* \| **--timetravel=**\ \ *USEC*
+ Modify the system time by *USEC* microseconds.
+ *USEC* may be prefixed with ``+`` or ``-`` (e.g. ``-T +300``).
+ This option is intended for debugging/testing only.
+
+**-t** \| **--test**
+ Run in test mode and exit when idle.
+
+**-v** \| **--version**
+ Print version information.
+
+See Also
+========
+
+taler-exchange-expire(1), taler-exchange-httpd(1), taler.conf(5).
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net/ or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-exchange-secmod-cs.1.rst b/manpages/taler-exchange-secmod-cs.1.rst
new file mode 100644
index 00000000..b75ce311
--- /dev/null
+++ b/manpages/taler-exchange-secmod-cs.1.rst
@@ -0,0 +1,76 @@
+taler-exchange-secmod-cs(1)
+###########################
+
+.. only:: html
+
+ Name
+ ====
+
+ **taler-exchange-secmod-cs** - handle private Clause-Schnorr key operations for a Taler exchange
+
+
+Synopsis
+========
+
+**taler-exchange-secmod-cs**
+[**-c** *FILENAME* | **--config=**\ \ *FILENAME*]
+[**-h** | **--help**]
+[**-L** *LOGLEVEL* | **--loglevel=**\ ‌\ *LOGLEVEL*]
+[**-l** *FILENAME* | **--logfile=**\ ‌\ *FILENAME*]
+[**-p** *N* | ,**--parallelism=**\ \ *N*]
+[**-T** *USEC* | **--timetravel=**\ \ *USEC*]
+[**-t** *TIMESTAMP* | **--time=**\ \ *TIMESTAMP*]
+[**-v** | **--version**]
+
+
+Description
+===========
+
+**taler-exchange-secmod-cs** is a command-line tool to
+handle private Clause-Schnorr key operations for a Taler exchange.
+
+FIXME: More details.
+
+Its options are as follows:
+
+**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
+ Use the configuration and other resources for the merchant to operate
+ from *FILENAME*.
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-L** *LOGLEVEL* \| **--loglevel=**\ ‌\ *LOGLEVEL*
+ Specifies the log level to use. Accepted values are: ``DEBUG``, ``INFO``,
+ ``WARNING``, ``ERROR``.
+
+**-l** *FILENAME* \| **--logfile=**\ ‌\ *FILENAME*
+ Send logging output to *FILENAME*.
+
+**p** *N* \| **--parallelism=**\ \ *N*
+ Run with *N* worker threads.
+
+**-T** *USEC* \| **--timetravel=**\ \ *USEC*
+ Modify the system time by *USEC* microseconds.
+ *USEC* may be prefixed with ``+`` or ``-`` (e.g. ``-T +300``).
+ This option is intended for debugging/testing only.
+
+**-t** *TIMESTAMP* \| **--time=**\ \ *TIMESTAMP*
+ Pretend it is *TIMESTAMP* for the update.
+ *TIMESTAMP* is a human-readable string (e.g., ``YYYY-MM-DD HH:MM:SS``).
+
+**-v** \| **--version**
+ Print version information.
+
+
+See Also
+========
+
+taler-exchange-httpd(1).
+
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-exchange-wire-gateway-client.1.rst b/manpages/taler-exchange-wire-gateway-client.1.rst
index 0533c35b..878ce39b 100644
--- a/manpages/taler-exchange-wire-gateway-client.1.rst
+++ b/manpages/taler-exchange-wire-gateway-client.1.rst
@@ -109,7 +109,7 @@ Options
See Also
========
-taler-bank-manage(1), taler.conf(5), https://docs.taler.net/core/api-wire.html#wire-transfer-test-apis
+taler.conf(5), https://docs.taler.net/core/api-wire.html#wire-transfer-test-apis
Bugs
====
diff --git a/manpages/taler-exchange-wirewatch.1.rst b/manpages/taler-exchange-wirewatch.1.rst
index 08bb6014..dbd0f2bc 100644
--- a/manpages/taler-exchange-wirewatch.1.rst
+++ b/manpages/taler-exchange-wirewatch.1.rst
@@ -14,6 +14,7 @@ Synopsis
**taler-exchange-wirewatch**
[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
[**-h** | **--help**]
+[**-I**_|_**--ignore-not-found**]
[**-L** *LOGLEVEL* | **--loglevel=**\ ‌\ *LOGLEVEL*]
[**-l** *FILENAME* | **--logfile=**\ ‌\ *FILENAME*]
[**-r** | **--reset**]
@@ -33,9 +34,16 @@ Its options are as follows:
Use the configuration and other resources for the exchange to operate
from *FILENAME*.
+**-f** *DELAY*\| **--longpoll-timeout=**\ \ *DELAY*
+ How long do we wait for a response for bank transactions from the bank. This is both the timeout for the long polling as well as the maximum frequency at which we would query the bank. Specified with unit (e.g. 30s, 1d, 2w), if no unit is given the number is interpreted in microseconds. Default is 60s.
+
**-h** \| **--help**
Print short help on options.
+**-I** \| **--ignore-not-found**
+ Do not fail if the bank says that the exchange bank account does not (yet) exist.
+ Keep trying.
+
**-L** *LOGLEVEL* \| **--loglevel=**\ ‌\ *LOGLEVEL*
Specifies the log level to use. Accepted values are: ``DEBUG``, ``INFO``,
``WARNING``, ``ERROR``.
diff --git a/manpages/taler-fakebank-run.1.rst b/manpages/taler-fakebank-run.1.rst
index eb608343..1a23cf24 100644
--- a/manpages/taler-fakebank-run.1.rst
+++ b/manpages/taler-fakebank-run.1.rst
@@ -17,6 +17,7 @@ Synopsis
[**-L** *LOGLEVEL* | **--loglevel=**\ ‌\ *LOGLEVEL*]
[**-l** *FILENAME* | **--logfile=**\ ‌\ *FILENAME*]
[**-n** *N* | **--num-threads=**\ \ *N*]
+[**-s** *AMOUNT* | **--signup-bonus=**\ \ *AMOUNT*]
[**-v** | **--version**]
Description
@@ -24,6 +25,8 @@ Description
**taler-fakebank-run** is a command-line tool to run a Taler "bank" API (HTTP REST service). The program is useful to provide the bank functionality for benchmarking or testing when LibEuFin is unavailable or otherwise unsuitable.
+It should be noted that the fakebank will keep a configured number of transactions in memory. If the number of transactions exceeds the configured memory limit, the fakebank will simply discard and overwrite the old entries. At that point, any requests involving such overwritten transactions will fail. Users of the fakebank are responsible for ensuring that the transaction history kept in memory is long enough for the purpose the bank is used for. The default limit is 128k entries.
+
Its options are as follows:
**-C** \| **--connection-close**
@@ -47,6 +50,9 @@ Its options are as follows:
**-n** *N* \| **--num-threads=**\ \ *N*
Use *N* threads in the thread pool.
+**-s** *AMOUNT* \| **--signup-bonus=**\ \ *AMOUNT*
+ Credit newly registered accounts with a balance of *AMOUNT*. Unlike other banks, this initial balance will be created out of thin air and not via a wire transfer from some bank-internal account.
+
**-v** \| **--version**
Print version information.
diff --git a/manpages/taler-helper-auditor-purses.1.rst b/manpages/taler-helper-auditor-purses.1.rst
new file mode 100644
index 00000000..09d23676
--- /dev/null
+++ b/manpages/taler-helper-auditor-purses.1.rst
@@ -0,0 +1,75 @@
+taler-helper-auditor-purses(1)
+##############################
+
+.. only:: html
+
+ Name
+ ====
+
+ **taler-helper-auditor-purses** - Audit Taler exchange purse handling
+
+
+Synopsis
+========
+
+**taler-helper-auditor-purses**
+[**-c** *FILENAME* | **--config=**\ \ *FILENAME*]
+[**-h** | **--help**]
+[**i** | **--internal**]
+[**-L** *LOGLEVEL* | **--loglevel=**\ ‌\ *LOGLEVEL*]
+[**-l** *FILENAME* | **--logfile=**\ ‌\ *FILENAME*]
+[**-m** *KEY* | **--exchange-key=**\ \ *KEY*]
+[**-T** *USEC* | **--timetravel=**\ \ *USEC*]
+[**-v** | **--version**]
+
+
+Description
+===========
+
+**taler-helper-auditor-purses** is a command-line tool to
+audit Taler exchange purse handling.
+
+FIXME: More detail.
+
+Its options are as follows:
+
+**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
+ Use the configuration and other resources for the auditor to operate
+ from *FILENAME*.
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-i** \| **--internal**
+ Perform checks only applicable for exchange-internal audits.
+
+**-L** *LOGLEVEL* \| **--loglevel=**\ ‌\ *LOGLEVEL*
+ Specifies the log level to use. Accepted values are: ``DEBUG``, ``INFO``,
+ ``WARNING``, ``ERROR``.
+
+**-l** *FILENAME* \| **--logfile=**\ ‌\ *FILENAME*
+ Send logging output to *FILENAME*.
+
+**-m** *KEY* \| **--exchange-key=**\ \ *KEY*
+ Use *KEY* (Crockford base32 encoded) as the public key of the exchange.
+
+**-T** *USEC* \| **--timetravel=**\ \ *USEC*
+ Modify the system time by *USEC* microseconds.
+ *USEC* may be prefixed with ``+`` or ``-`` (e.g. ``-T +300``).
+ This option is intended for debugging/testing only.
+
+**-v** \| **--version**
+ Print version information.
+
+
+See Also
+========
+
+taler-auditor(1), taler.conf(5).
+
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-mdb.1.rst b/manpages/taler-mdb.1.rst
new file mode 100644
index 00000000..5e6f86d2
--- /dev/null
+++ b/manpages/taler-mdb.1.rst
@@ -0,0 +1,73 @@
+taler-mdb(1)
+############
+
+.. only:: html
+
+ Name
+ ====
+
+ **taler-mdb** - Taler multi-drop bus vending machine integration
+
+
+Synopsis
+========
+
+**taler-mdb**
+[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
+[**-d** | **--disable-mdb**]
+[**-h** | **--help**]
+[**-i** | **--backlight-invert**]
+[**-L** _*LOGLEVEL* | **--log=**\ \ *LOGLEVEL*]
+[**-l** _*FILENAME* | **--logfile=**\ \ *FILENAME*]
+[**-s** | **--enable-soldout**]
+[**-t** | **--disable-tty**]
+[**-v** | **--version**]
+
+
+Description
+===========
+
+**taler-mdb** is a command-line tool to operate a vending machine using GNU Taler for payments.
+
+Its options are as follows:
+
+**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
+ Use the configuration and other resources for the Sync commands
+ to operate from *FILENAME*.
+
+**-d** \| **--disable-mdb**
+ Disable interaction with the MDB bus (for testing).
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-i** \| **--backlight-invert**
+ Invert the bit for turning on/off the backlight.
+
+**-L** *LOGLEVEL* \| **--log=**\ \ *LOGLEVEL*
+ Configure logging to use *LOGLEVEL*.
+
+**-l** *FILENAME* \| **--logfile=**\ \ *FILENAME*
+ Configure logging to write logs to *FILENAME*.
+
+**-s** \| **--enable-soldout**
+ When the machine fails to dispense a product, internally set the product to "sold out" and refuse future orders until restarted.
+
+**-t** \| **--disable-tty**
+ Disable interactive command-line use.
+
+**-v** \| **–version**
+ Print version information.
+
+
+See Also
+========
+
+taler-merchant-httpd(1), taler.conf(5).
+
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-merchant-benchmark.1.rst b/manpages/taler-merchant-benchmark.1.rst
index 2f91634a..7016c9d4 100644
--- a/manpages/taler-merchant-benchmark.1.rst
+++ b/manpages/taler-merchant-benchmark.1.rst
@@ -29,20 +29,16 @@ Subcommands
ordinary
Generate normal payments: all the payments are performed (by the
default instance) and aggregated by the exchange. Takes the following
- options.
+ option:
**-p** *PN* \| **--payments-number=**\ \ *PN*
Perform PN many payments, defaults to 1.
- **-t** *TN* \| **--tracks-number=**\ \ *TN*
- Perform TN many tracking operations, defaults to 1.
-
-
corner
Drive the generator to create unusual situations, like for example
leaving payments unaggregated, or using a non-default merchant
- instance. Takes the following options.
+ instance. Takes the following options:
**-t** *TC* \| **--two-coins=**\ \ *TC*
@@ -67,8 +63,7 @@ Common Options
Use the configuration and other resources for the merchant to
operate from FILENAME.
-**-e** *SECTION* \| **--exchange-account=**\ \ *SECTION*
- Mandatory.
+**-u** *SECTION* \| **--exchange-account-section=**\ \ *SECTION*
Configuration *SECTION* specifying the exchange account to use.
**-h** \| **--help**
@@ -88,7 +83,7 @@ Common Options
See Also
========
-taler-merchant-dbinit(1), taler-merchant-tip-enable(1), taler.conf(5)
+taler-merchant-dbinit(1), taler.conf(5)
Bugs
diff --git a/manpages/taler-merchant-dbconfig.1.rst b/manpages/taler-merchant-dbconfig.1.rst
new file mode 100644
index 00000000..f2055710
--- /dev/null
+++ b/manpages/taler-merchant-dbconfig.1.rst
@@ -0,0 +1,61 @@
+taler-merchant-dbconfig(1)
+##########################
+
+.. only:: html
+
+ Name
+ ====
+
+ **taler-merchant-dbconfig** - configure Taler merchant database
+
+
+Synopsis
+========
+
+**taler-merchant-dbconfig**
+[**-c** *FILENAME*]
+[**-h**]
+[**-n** *NAME*]
+[**-r**]
+[**-s**]
+[**-u** *USER*]
+
+Description
+===========
+
+**taler-merchant-dbconfig** is a simple shell script that configures
+a Postgresql database for use by the GNU Taler merchant.
+
+Its options are as follows:
+
+**-c** *FILENAME*
+ Write the database configuration to FILENAME. The tool
+ will append the required ``CONFIG`` option for the
+ Postgresql access to the respective file.
+
+**-h**
+ Print short help on options.
+
+**-n** *DBNAME*
+ Use DBNAME for the name of the created database.
+
+**-r**
+ Reset any existing database. Looses all existing data. DANGEROUS.
+
+**-s**
+ Skip database initialization. Useful if you want to run
+ ``taler-merchant-dbinit`` manually.
+
+**-u** *USER*
+ Specifies the (main) merchant user that will access the database.
+
+See Also
+========
+
+taler-merchant-dbinit(1), taler.conf(5).
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-merchant-depositcheck.1.rst b/manpages/taler-merchant-depositcheck.1.rst
new file mode 100644
index 00000000..e243f0d2
--- /dev/null
+++ b/manpages/taler-merchant-depositcheck.1.rst
@@ -0,0 +1,78 @@
+taler-merchant-depositcheck(1)
+##############################
+
+.. only:: html
+
+ Name
+ ====
+
+ **taler-merchant-depositcheck** - check if deposits are associated with wire transfers
+
+
+Synopsis
+========
+
+**taler-merchant-depositcheck**
+[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
+[**-e** *BASE_URL* | **--exchange=**\ \ *BASE_URL*]
+[**-h** | **--help**]
+[**-L** *LOGLEVEL* | **--loglevel=**\ ‌\ *LOGLEVEL*]
+[**-l** *FILENAME* | **--logfile=**\ ‌\ *FILENAME*]
+[**-T** *USEC* | **--timetravel**\ \ *USEC*]
+[**-t** | **--test**]
+[**-v** | **--version**]
+
+Description
+===========
+
+**taler-merchant-depositcheck** is a command-line tool to inquire with exchanges about whether they completed
+bank transfers in response to deposits made by the
+merchant backend. This will allow the merchant backend to detect deposit issues, for example if a KYC is blocking
+a wire transfer.
+
+Its options are as follows:
+
+**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
+ Use the configuration and other resources for the merchant to operate
+ from *FILENAME*.
+
+**-e** *BASE_URL* \| **--exchange=**\ ‌\ *BASE_URL*
+ Base URL of the exchange to monitor. If not given, a worker process will be spawned for each exchange in the configuration ("merchant-exchange-" sections).
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-L** *LOGLEVEL* \| **--loglevel=**\ ‌\ *LOGLEVEL*
+ Specifies the log level to use. Accepted values are: ``DEBUG``, ``INFO``,
+ ``WARNING``, ``ERROR``.
+
+**-l** *FILENAME* \| **--logfile=**\ ‌\ *FILENAME*
+ Send logging output to *FILENAME*.
+
+**-s** *SECTION* \| **--section=**\ \ *SECTION*
+ Configuration section to use. Default is taler-merchant-depositcheck. Needed
+ if different processes are used to watch multiple bank accounts (for the
+ same instance or different instances).
+
+**-T** *USEC* \| **--timetravel=**\ \ *USEC*
+ Modify the system time by *USEC* microseconds.
+ *USEC* may be prefixed with ``+`` or ``-`` (e.g. ``-T +300``).
+ This option is intended for debugging/testing only.
+
+**-t** \| **--test**
+ Run in test mode. Only runs until the current list of bank
+ transactions are all imported.
+
+**-v** \| **–version**
+ Print version information.
+
+See Also
+========
+
+taler-merchant-httpd(1), taler.conf(5).
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-merchant-exchange.1.rst b/manpages/taler-merchant-exchange.1.rst
new file mode 100644
index 00000000..de2b571f
--- /dev/null
+++ b/manpages/taler-merchant-exchange.1.rst
@@ -0,0 +1,73 @@
+taler-merchant-exchange(1)
+##########################
+
+.. only:: html
+
+ Name
+ ====
+
+ **taler-merchant-exchange** - reconcile bank transfers with Taler exchange
+
+
+Synopsis
+========
+
+**taler-merchant-exchange**
+[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
+[**-h** | **--help**]
+[**-L** *LOGLEVEL* | **--loglevel=**\ ‌\ *LOGLEVEL*]
+[**-l** *FILENAME* | **--logfile=**\ ‌\ *FILENAME*]
+[**-T** *USEC* | **--timetravel**\ \ *USEC*]
+[**-t** | **--test**]
+[**-v** | **--version**]
+
+Description
+===========
+
+**taler-merchant-exchange** is a background job that reconciles
+wire transfers that credit the merchant's bank account with
+the respective contracts that have been paid by asking the
+exchange to provide a list of all deposits that were aggregated
+into a wire transfer.
+
+The tool is part of a set of processes that allow a merchant backend to
+validate that the exchange paid the merchant correctly.
+
+Its options are as follows:
+
+**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
+ Use the configuration and other resources for the merchant to operate
+ from *FILENAME*.
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-L** *LOGLEVEL* \| **--loglevel=**\ ‌\ *LOGLEVEL*
+ Specifies the log level to use. Accepted values are: ``DEBUG``, ``INFO``,
+ ``WARNING``, ``ERROR``.
+
+**-l** *FILENAME* \| **--logfile=**\ ‌\ *FILENAME*
+ Send logging output to *FILENAME*.
+
+**-T** *USEC* \| **--timetravel=**\ \ *USEC*
+ Modify the system time by *USEC* microseconds.
+ *USEC* may be prefixed with ``+`` or ``-`` (e.g. ``-T +300``).
+ This option is intended for debugging/testing only.
+
+**-t** \| **--test**
+ Run in test mode. Only runs until the current list of bank
+ transactions have all been checked.
+
+**-v** \| **–version**
+ Print version information.
+
+See Also
+========
+
+taler-merchant-depositcheck(1), taler-merchant-wirewatch(1), taler.conf(5).
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-merchant-httpd.1.rst b/manpages/taler-merchant-httpd.1.rst
index 5ea47c12..3df4f4ac 100644
--- a/manpages/taler-merchant-httpd.1.rst
+++ b/manpages/taler-merchant-httpd.1.rst
@@ -13,6 +13,7 @@ Synopsis
========
**taler-merchant-httpd**
+[**-a**_|_**--auth**]
[**-C** | **--connection-close**]
[**-c** *FILENAME* | **--config=**\ \ *FILENAME*]
[**-h** | **--help**]
@@ -33,9 +34,9 @@ Options
=======
**-a** *TOKEN* \| **--auth=**\ \ *TOKEN*
- Use TOKEN for initial access control to the merchant backend. The value
+ Use TOKEN for initial access control to the merchant backend. TOKEN must start with the "secret-token:" prefix, as per RFC 8959. The value
given in TOKEN must appear in backoffice requests to the default instance
- of the merchant, i.e. "Authorization: Bearer secret-token:TOKEN" to obtain
+ of the merchant, i.e. "Authorization: Bearer TOKEN" to obtain
access to the merchant backend. Note that setting a passphrase for the
default instance by any means will block future access via TOKEN. This
is basically a way to reset the passphrase protecting access. TOKEN
@@ -92,7 +93,7 @@ TALER_MERCHANT_TOKEN
See Also
========
-taler-merchant-dbinit(1), taler-merchant-tip-enable(1), taler.conf(5)
+taler-merchant-dbinit(1), taler-merchant-setup-reserve(1), taler.conf(5)
Bugs
diff --git a/manpages/taler-merchant-passwd.1.rst b/manpages/taler-merchant-passwd.1.rst
new file mode 100644
index 00000000..6cb102b2
--- /dev/null
+++ b/manpages/taler-merchant-passwd.1.rst
@@ -0,0 +1,64 @@
+taler-merchant-passwd(1)
+########################
+
+.. only:: html
+
+ Name
+ ====
+
+ **taler-merchant-passwd** - reset password of existing instance
+
+
+Synopsis
+========
+
+**taler-merchant-passwd**
+[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
+[**-h** | **--help**]
+[**-L** *LOGLEVEL* | **--loglevel=**\ ‌\ *LOGLEVEL*]
+[**-l** *FILENAME* | **--logfile=**\ ‌\ *FILENAME*]
+[**-i**_*NAME* | **--instance**\ \ *NAME*]
+[**-v** | **--version**]
+[PASSWORD]
+
+Description
+===========
+
+**taler-merchant-passwd** is a command-line tool to reset passwords
+of existing Taler instances. The password must either be specified
+as the last command-line argument or in the TALER_MERCHANT_PASSWORD
+environment variable.
+
+Its options are as follows:
+
+**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
+ Use the configuration and other resources for the merchant to operate
+ from *FILENAME*.
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-i** *NAME* \| **--instance**\ \ *NAME*
+ Specifies the name of the instance for which the password should be
+ updated. If not given, the "default" instance is modified.
+
+**-L** *LOGLEVEL* \| **--loglevel=**\ ‌\ *LOGLEVEL*
+ Specifies the log level to use. Accepted values are: ``DEBUG``, ``INFO``,
+ ``WARNING``, ``ERROR``.
+
+**-l** *FILENAME* \| **--logfile=**\ ‌\ *FILENAME*
+ Send logging output to *FILENAME*.
+
+**-v** \| **–version**
+ Print version information.
+
+See Also
+========
+
+taler-merchant-httpd(1), taler.conf(5).
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-merchant-setup-reserve.1.rst b/manpages/taler-merchant-setup-reserve.1.rst
deleted file mode 100644
index 25d5b102..00000000
--- a/manpages/taler-merchant-setup-reserve.1.rst
+++ /dev/null
@@ -1,119 +0,0 @@
-taler-merchant-setup-reserve(1)
-###############################
-
-
-.. only:: html
-
- Name
- ====
-
- **taler-merchant-setup-reserve** - setup reserve for tipping
-
-
-Synopsis
-========
-
-**taler-merchant-setup-reserve**
-[**-A** *USERNAME:PASSWORD* | **--auth=**\ \ *USERNAME:PASSWORD*]
-[**-a** *VALUE* | **--amount=**\ \ *VALUE*]
-[**-C** *CERTFILE* | **--cert=**\ \ *CERTFILE*]
-[**-c** *FILENAME* | **--config=**\ \ *FILENAME*]
-[**-e** *URL* | **--exchange-url=**\ \ *URL*]
-[**-h** | **--help**]
-[**-k** *KEYFILE* | **--key=**\ \ *KEYFILE*]
-[**-L** *LOGLEVEL* | **--loglevel=**\ ‌\ *LOGLEVEL*]
-[**-l** *FILENAME* | **--logfile=**\ ‌\ *FILENAME*]
-[**-m** *URL* | **--merchant-url=**\ \ *URL*]
-[**-p** *KEYFILEPASSPHRASE* | **--pass=**\ \ *KEYFILEPASSPHRASE*]
-[**-t** *CERTTYPE* | **--type=**\ \ *CERTTYPE*]
-[**-w** *METHOD* | **--wire-method=**\ \ *METHOD*]
-[**-v** | **--version**]
-
-
-Description
-===========
-
-**taler-merchant-setup-reserve** is a command-line tool to setup a reserve
-(creating the private reserve key) and obtaining the wire transfer information
-from the exchange needed to fill the reserve.
-
-
-Options
-=======
-
-**-A** *USERNAME:PASSWORD* \| **--auth=**\ \ *USERNAME:PASSWORD*
- Use ``USERNAME`` and ``PASSWORD`` for HTTP client authentication.
- The ":" must be present as a separator.
- Note that this form of authentication has nothing to do with the TLS client
- certificate authentication supported with the ``-C``, ``-k`` and ``-p`` options.
- The ``PASSWORD`` given to this option is given to the server!
-
-**-a** *VALUE* \| **--amount=**\ \ *VALUE*
- Mandatory.
- Amount to be transferred to the reserve.
-
-**-C** *CERTFILE* \| **--cert=**\ \ *CERTFILE*
- The specified ``CERTFILE`` contains a TLS client certificate to be used to
- authenticate the client. See also ``-t``.
-
-**-c** *FILENAME* \| **--config=**\ \ *FILENAME*
- Use the configuration and other resources for the merchant to
- operate from ``FILENAME``.
-
-**-e** *URL* \| **--exchange-url=**\ \ *URL*
- Mandatory.
- Use ``URL`` for the exchange base URL.
- This is the exchange where the reserve will be created.
- The currency used in the amount specification must be offered by this exchange.
-
-**-h** \| **--help**
- Print short help on options.
-
-**-k** *KEYFILE* \| **--key=**\ \ *KEYFILE*
- The specified ``KEYFILE`` contains a TLS client private key to be used to
- authenticate the client. See also ``-p`` and ``-C``.
-
-**-L** *LOGLEVEL* \| **--loglevel=**\ ‌\ *LOGLEVEL*
- Specifies the log level to use. Accepted values are: ``DEBUG``, ``INFO``,
- ``WARNING``, ``ERROR``.
-
-**-l** *FILENAME* \| **--logfile=**\ ‌\ *FILENAME*
- Send logging output to *FILENAME*.
-
-**-m** *URL* \| **--merchant-url=**\ \ *URL*
- Mandatory.
- Use ``URL`` as the merchant base URL.
- Should include the path to the instance if the reserve is to be
- created for a non-default instance.
-
-**-p** *KEYFILEPASSPHRASE* \| **--pass=**\ \ *KEYFILEPASSPHRASE*
- The specified ``KEYFILEPASSPHRASE`` is to be used to decrypt the KEYFILE.
- See also ``-k``. Not to be confused with ``-A``.
- The ``KEYFILEPASSPHRASE`` given here is only used locally to decrypt the KEYFILE.
-
-**-t** *CERTTYPE* \| **--type=**\ \ *CERTTYPE*
- The specified CERTFILE contains a TLS client certificate of ``CERTTYPE``.
- Default is ``PEM``. See also ``-C``.
-
-**-w** *METHOD* \| **--wire-method=**\ \ *METHOD*
- Mandatory.
- Which wire method should be used.
- Needed to select the wire transfer method of the exchange.
- The method must be supported by the exchange.
- Typical values would be ``iban`` or ``x-taler-bank``.
-
-**-v** \| **--version**
- Print version information.
-
-
-See Also
-========
-
-taler-merchant-dbinit(1), taler.conf(5)
-
-
-Bugs
-====
-
-Report bugs by using https://bugs.taler.net/ or by sending electronic
-mail to <taler@gnu.org>.
diff --git a/manpages/taler-merchant-webhook.1.rst b/manpages/taler-merchant-webhook.1.rst
new file mode 100644
index 00000000..c3a71509
--- /dev/null
+++ b/manpages/taler-merchant-webhook.1.rst
@@ -0,0 +1,68 @@
+taler-merchant-webhook(1)
+#########################
+
+.. only:: html
+
+ Name
+ ====
+
+ **taler-merchant-webhook** - run webhooks of Taler merchant backend
+
+
+Synopsis
+========
+
+**taler-merchant-webhook**
+[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
+[**-h** | **--help**]
+[**-L** *LOGLEVEL* | **--loglevel=**\ ‌\ *LOGLEVEL*]
+[**-l** *FILENAME* | **--logfile=**\ ‌\ *FILENAME*]
+[**-T** *USEC* | **--timetravel**\ \ *USEC*]
+[**-t** | **--test**]
+[**-v** | **--version**]
+
+Description
+===========
+
+**taler-merchant-webhook** is a command-line tool to trigger webhooks
+scheduled by a Taler merchant backend. It makes the necessary HTTP
+requests and updates the Taler merchant database accordingly.
+
+Its options are as follows:
+
+**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
+ Use the configuration and other resources for the merchant to operate
+ from *FILENAME*.
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-L** *LOGLEVEL* \| **--loglevel=**\ ‌\ *LOGLEVEL*
+ Specifies the log level to use. Accepted values are: ``DEBUG``, ``INFO``,
+ ``WARNING``, ``ERROR``.
+
+**-l** *FILENAME* \| **--logfile=**\ ‌\ *FILENAME*
+ Send logging output to *FILENAME*.
+
+**-T** *USEC* \| **--timetravel=**\ \ *USEC*
+ Modify the system time by *USEC* microseconds.
+ *USEC* may be prefixed with ``+`` or ``-`` (e.g. ``-T +300``).
+ This option is intended for debugging/testing only.
+
+**-t** \| **--test**
+ Run in test mode. Only runs until there are no more webhooks
+ to be executed.
+
+**-v** \| **–version**
+ Print version information.
+
+See Also
+========
+
+taler-merchant-httpd(1), taler.conf(5).
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-merchant-wirewatch.1.rst b/manpages/taler-merchant-wirewatch.1.rst
new file mode 100644
index 00000000..e2f9d1df
--- /dev/null
+++ b/manpages/taler-merchant-wirewatch.1.rst
@@ -0,0 +1,78 @@
+taler-merchant-wirewatch(1)
+###########################
+
+.. only:: html
+
+ Name
+ ====
+
+ **taler-merchant-wirewatch** - import bank transfers into Taler merchant backend
+
+
+Synopsis
+========
+
+**taler-merchant-wirewatch**
+[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
+[**-h** | **--help**]
+[**-L** *LOGLEVEL* | **--loglevel=**\ ‌\ *LOGLEVEL*]
+[**-l** *FILENAME* | **--logfile=**\ ‌\ *FILENAME*]
+[**-p** | **--persist**]
+[**-T** *USEC* | **--timetravel**\ \ *USEC*]
+[**-t** | **--test**]
+[**-v** | **--version**]
+
+Description
+===========
+
+**taler-merchant-wirewatch** is a command-line tool to import
+information about incoming bank transfers into a Taler merchant
+backend. This will allow the merchant backend to validate that
+the exchange paid the merchant correctly.
+
+Its options are as follows:
+
+**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
+ Use the configuration and other resources for the merchant to operate
+ from *FILENAME*.
+
+**-h** \| **--help**
+ Print short help on options.
+
+**-L** *LOGLEVEL* \| **--loglevel=**\ ‌\ *LOGLEVEL*
+ Specifies the log level to use. Accepted values are: ``DEBUG``, ``INFO``,
+ ``WARNING``, ``ERROR``.
+
+**-l** *FILENAME* \| **--logfile=**\ ‌\ *FILENAME*
+ Send logging output to *FILENAME*.
+
+**-p** \| **--persist**
+ Run in persist mode. Does not exit when the account configuration changes. Useful when not running under systemd.
+
+**-s** *SECTION* \| **--section=**\ \ *SECTION*
+ Configuration section to use. Default is taler-merchant-wirewatch. Needed
+ if different processes are used to watch multiple bank accounts (for the
+ same instance or different instances).
+
+**-T** *USEC* \| **--timetravel=**\ \ *USEC*
+ Modify the system time by *USEC* microseconds.
+ *USEC* may be prefixed with ``+`` or ``-`` (e.g. ``-T +300``).
+ This option is intended for debugging/testing only.
+
+**-t** \| **--test**
+ Run in test mode. Only runs until the current list of bank
+ transactions are all imported.
+
+**-v** \| **–version**
+ Print version information.
+
+See Also
+========
+
+taler-merchant-httpd(1), taler.conf(5).
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-terms-generator.1.rst b/manpages/taler-terms-generator.1.rst
new file mode 100644
index 00000000..d6c22411
--- /dev/null
+++ b/manpages/taler-terms-generator.1.rst
@@ -0,0 +1,72 @@
+taler-terms-generator(1)
+########################
+
+
+.. only:: html
+
+ Name
+ ====
+
+ **taler-terms-generator** - generate legal terms for GNU Taler services
+
+
+Synopsis
+========
+
+**taler-terms-generator**
+[**-a** *AUTHOR*]
+[**-C** *COPYRIGHT*]
+[**-h**]
+[**-i** *INPUT*]
+[**-l** *LANGUAGE*]
+[**-o** *OUTPUT*]
+[**-p** *PAPER*]
+[**-t** *TITLE*]
+
+
+Description
+===========
+
+**taler-terms-generator** is a command-line tool to create terms of service
+ and privacy policy files in various file formats and languages from a
+ reStructuredText (".rst") input. It can be used to generate the responses
+ various GNU Taler services serve under the ``/terms`` and ``/pp`` endpoints.
+
+**-a** *AUTHOR*
+ set the author information to the given AUTHOR in the meta-data of various generated outputs.
+
+**-C** *COPYRIGHT*
+ set the copyright information to the given COPYRIGHT in the meta-data of various generated outputs.
+
+**-h** \| **--help**
+ Prints a compiled-in help text.
+
+**-i** *INPUT*
+ Name of the input (.rst) file with the terms of service or privacy policy to convert.
+
+**-l** *LANGUAGE*
+ Add the given *LANGUAGE* to the list of translations for the current *INPUT*. *LANGUAGE* must be a two-letter language code (like "de" or "it"). This will generate or update the respective ".po" files to translate the *INPUT* terms to this *LANGUAGE*.
+
+**-L** *LOCALE_DIR*
+ Specify locale/ directory where GNU gettext resources for translating the input are located. If "-l" is given, this directory is where fresh or updated ".po" files will be placed, and otherwise this directory will be scanned for translations of the ".rst" input file.
+
+**-o** *OUTPUT*
+ Specifies where to write the output. This should be the directory where the service expects to find the generated resources. Unless you changed the default configuration, you probably do not have to specify this value.
+
+**-p** *PAPER*
+ Specifies the paper format for generated PDF documents. Can be "a4" or "letter".
+
+**-t** *TITLE*
+ Overrides the document title. By default, the title will be set to the contents of the first line of the *INPUT* ".rst" file.
+
+
+See Also
+========
+
+taler-config(1), taler.conf(5)
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net/ or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-unified-setup.1.rst b/manpages/taler-unified-setup.1.rst
new file mode 100644
index 00000000..fe60d1e5
--- /dev/null
+++ b/manpages/taler-unified-setup.1.rst
@@ -0,0 +1,110 @@
+taler-unified-setup.sh(1)
+#########################
+
+
+.. only:: html
+
+ Name
+ ====
+
+ **taler-unified-setup.sh** - conveniently launch GNU Taler services
+
+
+Synopsis
+========
+
+**taler-unified-setup**
+[**-a**]
+[**-b**]
+[**-c** *CONFIG_FILENAME*]
+[**-d** *METHOD*]
+[**-e**]
+[**-f**]
+[**-h**]
+[**-k**]
+[**-l** *FILENAME*]
+[**-m**]
+[**-n**]
+[**-r** *MEX*]
+[**-s**]
+[**-t**]
+[**-u** *SECTION*]
+[**-v**]
+[**-w**]
+
+
+Description
+===========
+
+**taler-unified-setup** is a command-line tool to launch and stop
+GNU Taler services in bulk. It is usually used in test cases or
+for development. For production, services should be launched via
+systemd and not via this tool.
+
+**-a**
+ Start auditor
+
+**-b**
+ Start backup/sync service
+
+**-c** *CONFIG_FILENAME*
+ (Mandatory) Use CONFIG_FILENAME.
+
+**-d** *METHOD*
+ use the given wire method. Default is 'x-taler-bank'.
+
+**-e**
+ Start exchange
+
+**-f**
+ Start fakebank
+
+**-g**
+ Start aggregator
+
+**-h** \| **--help**
+ Prints a compiled-in help text.
+
+**-k**
+ Start challenger (KYC service)
+
+**-L** *LOGLEVEL*
+ Specifies the log level to use. Accepted values are: ``DEBUG``, ``INFO``,
+ ``WARNING``, ``ERROR``.
+
+**-m**
+ Start merchant
+
+**-n**
+ Start libeufin nexus
+
+**-r** *MEX*
+ Which exchange to use at the merchant
+
+**-s**
+ Start libeufin sandbox
+
+**-t**
+ Start taler-exchange-transfer
+
+**-u** *SECTION*
+ Specifies configuration section with the exchange account to use
+
+**-v**
+ Use valgrind
+
+**-w**
+ Start taler-exchange-wirewatch
+
+
+See Also
+========
+
+taler-exchange-dbinit(1), taler-exchange-offline(1), taler-merchant-benchmark(1),
+taler-exchange-httpd(1), taler.conf(5)
+
+Bugs
+====
+
+Report bugs by using https://bugs.taler.net/ or by sending electronic
+mail to <taler@gnu.org>.
diff --git a/manpages/taler-wallet-cli.1.rst b/manpages/taler-wallet-cli.1.rst
index bac9ea9f..dad790f5 100644
--- a/manpages/taler-wallet-cli.1.rst
+++ b/manpages/taler-wallet-cli.1.rst
@@ -46,8 +46,6 @@ for testing.
**withdraw-uri** URI
-**tip-uri** URI
-
**refund-uri** URI
**pay-uri** [**-y** | **--yes**] URI
diff --git a/manpages/taler.conf.5.rst b/manpages/taler.conf.5.rst
index 1a366608..3074f68b 100644
--- a/manpages/taler.conf.5.rst
+++ b/manpages/taler.conf.5.rst
@@ -12,37 +12,7 @@ taler.conf(5)
Description
===========
-The configuration file is line-oriented.
-Blank lines and whitespace at the beginning and end of a line are ignored.
-Comments start with ``#`` or ``%`` in the first column
-(after any beginning-of-line whitespace) and go to the end of the line.
-
-The file is split into sections.
-Every section begins with “[SECTIONNAME]” and
-contains a number of options of the form “OPTION=VALUE”.
-There may be whitespace around the ``=`` (equal sign).
-Section names and options are *case-insensitive*.
-
-The values, however, are *case-sensitive*.
-In particular, boolean values are one of ``YES`` or ``NO``.
-Values can include whitespace by surrounding
-the entire value with ``"`` (double quote).
-Note, however, that there are no escape characters in such strings;
-all characters between the double quotes (including other double quotes)
-are taken verbatim.
-
-Values that represent filenames can begin with a ``/bin/sh``-like
-variable reference.
-This can be simple, such as ``$TMPDIR/foo``, or complex,
-such as ``${TMPDIR:-${TMP:-/tmp}}/foo``.
-See ``[PATHS]`` (below).
-
-Values that represent a time duration are represented as a series of one or
-more ``NUMBER UNIT`` pairs, e.g. ``60 s``, ``4 weeks 1 day``, ``5 years 2 minutes``.
-
-Values that represent an amount are in the usual amount syntax:
-``CURRENCY:VALUE.FRACTION``, e.g. ``EUR:1.50``.
-The ``FRACTION`` portion may extend up to 8 places.
+.. include:: ../frags/common-conf-syntax.rst
Files containing default values for many of the options described below
are installed under ``$TALER_PREFIX/share/taler/config.d/``.
@@ -62,11 +32,19 @@ GLOBAL OPTIONS
--------------
The following options are from the “[taler]” section and used by
-virtually all Taler components.
+virtually all Taler components. Note: work is ongoing to obsolete
+these options, but for now they are in use.
+
CURRENCY
Name of the currency, e.g. “EUR” for Euro.
+CURRENCY_ROUND_UNIT
+ Smallest amount in this currency that can be transferred using the
+ underlying RTGS. For example: "EUR:0.01" or "JPY:1".
+
+
+
The “[PATHS]” section is special in that it contains paths that can be
referenced using “$” in other configuration values that specify
filenames. For Taler, it commonly contains the following paths:
@@ -91,6 +69,62 @@ TALER_RUNTIME_DIR
Where should Taler store system runtime data (like UNIX domain
sockets). Usually “${TMP}/taler-system-runtime”.
+
+CURRENCY SPECIFICATIONS
+-----------------------
+
+Sections with a name of the form “[currency-$NAME]” (where "$NAME" could
+be any unique string) are used to specify details about how currencies
+should be handled (and in particularly rendered) by the user interface.
+A detailed motivation for this section can be found in DD51.
+Different components can have different rules for the same currency. For
+example, a bank or merchant may decide to render Euros or Dollars with
+always exactly two fractional decimals, while an Exchange for the same
+currency may support additional decimals. The required options in each
+currency specification section are:
+
+ENABLED
+ Set to YES or NO. If set to NO, the currency specification
+ section is ignored. Can be used to disable currencies or
+ select alternative sections for the same CODE with different
+ choices.
+
+CODE
+ Code name for the currency. Can be at most 11 characters,
+ only the letters A-Z are allowed. Primary way to identify
+ the currency in the protocol.
+
+NAME
+ Long human-readable name for the currency. No restrictions,
+ but should match the official name in English.
+
+FRACTIONAL_INPUT_DIGITS
+ Number of fractional digits that users are allowed to enter
+ manually in the user interface.
+
+FRACTIONAL_NORMAL_DIGITS
+ Number of fractional digits that will be rendered normally
+ (in terms of size and placement). Digits shown beyond this
+ number will typically be rendered smaller and raised (if
+ possible).
+
+FRACTIONAL_TRAILING_ZERO_DIGITS
+ Number of fractional digits to pad rendered amounts with
+ even if these digits are all zero. For example, use 2 to
+ render 1 USD as $1.00.
+
+ALT_UNIT_NAMES
+ JSON map determining how to encode very large or very tiny
+ amounts in this currency. Maps a base10 logarithm to the
+ respective currency symbol. Must include at least an
+ entry for 0 (currency unit). For example, use
+ {"0":"€"} for Euros or "{"0":"$"} for Dollars. You could
+ additionally use {"0":"€","3":"k€"} to render 3000 EUR
+ as 3k€. For BTC a typical map would be
+ {"0":"BTC","-3":"mBTC"}, informing the UI to render small
+ amounts in milli-Bitcoin (mBTC).
+
+
EXCHANGE OPTIONS
----------------
@@ -100,20 +134,59 @@ exchange tools.
DB
Plugin to use for the database, e.g. “postgres”.
+SERVE
+ Should the HTTP server listen on a UNIX domain socket (set option to "unix") or on a TCP socket (set option to "tcp")?
+
+UNIXPATH
+ Path to listen on if we "SERVE" is set to "unix".
+
+UNIXPATH_MODE
+ Access permission mask to use for the "UNIXPATH".
+
PORT
Port on which the HTTP server listens, e.g. 8080.
+BIND_TO
+ Hostname to which the exchange HTTP server should be bound to, e.g. "localhost".
+
MASTER_PUBLIC_KEY
Crockford Base32-encoded master public key, public version of the
- exchange's long-time offline signing key.
+ exchange's long-time offline signing key. This configuration option
+ is also used by the **auditor** to determine the public key of the
+ exchange which it is auditing.
-MASTER_PRIV_FILE
- Location of the master private key on disk. Only used by tools that
- can be run offline (as the master key is for offline signing).
+AML_THRESHOLD
+ Largest amount in this currency that can be transferred per month without
+ an AML staff member doing a (manual) AML check. For example: "USD:1000000".
+
+KYC_AML_TRIGGER
+ Program to run on KYC attribute data to decide whether we should immediately flag an account for AML review. Program must return 0 if a manual AML review is not needed, and non-zero to trigger an AML review. The KYC attribute data of the new user will be passed on standard-input.
+
+STEFAN_ABS
+ Absolute amount to add as an offset in the STEFAN fee approximation
+ curve (see DD47). Defaults to CURRENCY:0 if not specified.
+
+STEFAN_LOG
+ Amount to multiply by the base-2 logarithm of the total amount
+ divided by the amount of the smallest denomination
+ in the STEFAN fee approximation curve (see DD47).
+ Defaults to CURRENCY:0 if not specified.
+
+STEFAN_LIN
+ Linear floating point factor to be multiplied by the total amount
+ to use in the STEFAN fee approximation curve (see DD47).
+ Defaults to 0.0 if not specified.
BASE_URL
The base URL under which the exchange can be reached.
Added to wire transfers to enable tracking by merchants.
+ Used by the KYC logic when interacting with OAuth 2.0.
+
+TOPLEVEL_REDIRECT_URL
+ Where to redirect visitors that access the top-level
+ "/" endpoint of the exchange. Should point users to
+ information about the exchange operator.
+ Optional setting, defaults to "/terms".
AGGREGATOR_IDLE_SLEEP_INTERVAL
For how long should the taler-exchange-aggregator sleep when it is idle
@@ -140,6 +213,9 @@ SIGNKEY_LEGAL_DURATION
MAX_KEYS_CACHING
For how long should clients cache ``/keys`` responses at most?
+MAX_REQUESTS
+ How many requests should the HTTP server process at most before committing suicide?
+
TERMS_DIR
Directory where the terms of service of the exchange operator can be fund.
The directory must contain sub-directories for every supported language,
@@ -175,13 +251,167 @@ PRIVACY_ETAG
Works the same as ``TERMS_ETAG``, just for the privacy policy.
+EXCHANGE KYC PROVIDER OPTIONS
+-----------------------------
+
+The following options must be in the section "[kyc-provider-XXX]" sections.
+
+COST
+ Relative cost of the KYC provider, non-negative number.
+
+LOGIC
+ API type of the KYC provider.
+
+USER_TYPE
+ Type of user this provider is for, either INDIVIDUAL or BUSINESS.
+
+PROVIDED_CHECKS
+ List of checks performed by this provider. Space-separated names of checks, must match check names in legitimization rules.
+
+
+EXCHANGE KYC OAUTH2 OPTIONS
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following options must be in the section "[kyc-provider-XXX]" sections with "LOGIC = oauth2".
+
+
+KYC_OAUTH2_VALIDITY
+ Duration (e.g. "12 months") of the validity of the performed KYC check. Can be "forever".
+
+KYC_OAUTH2_AUTHORIZE_URL
+ URL of the OAuth2 endpoint to be used for KYC checks. The authorize URL is where the exchange will redirect the client to begin the authorization process. Example: "http://localhost:8888/oauth/v2/authorize". To use the plugin in combination with the Challenger service's ``/setup`` step, append "#setup", thus "https://challenger.example.com/authorize#setup". Here, "#setup" is not a fragment but merely a hint to the logic to determine the full authorization URL via the ``/setup/$CLIENT_ID`` handler.
+
+KYC_OAUTH2_TOKEN_URL
+ URL of the OAuth2 endpoint to be used for KYC checks. This is where the server will ultimately send the authorization token from the client and obtain its access token (which currently must be a "bearer" token). Example: "http://localhost:8888/oauth/v2/token" (or just "/token")
+
+KYC_OAUTH2_INFO_URL
+ URL of the OAuth2-protected resource endpoint, where the OAuth 2.0 token can be used to download information about the user that has undergone the KYC process. The exchange will use the access token obtained from the KYC_AUTH2_AUTH_URL to show that it is authorized to obtain the details. Example: "http://localhost:8888/api/user/me" or "http://localhost:8888/oauth/v2/info"
+
+KYC_OAUTH2_CLIENT_ID
+ Client ID of the exchange when it talks to the KYC OAuth2 endpoint.
+
+KYC_OAUTH2_CLIENT_SECRET
+ Client secret of the exchange to use when talking to the KYC Oauth2 endpoint.
+
+KYC_OAUTH2_POST_URL
+ URL to which the exchange will redirect the client's browser after successful authorization/login for the KYC process. Example: "http://example.com/thank-you"
+
+KYC_OAUTH2_CONVERTER_HELPER
+ Helper to convert JSON with KYC data returned by the OAuth2.0 info endpoint into GNU Taler internal format. Specific to the OAuth 2.0 provider.
+
+KYC_OAUTH2_DEBUG_MODE
+ Set to YES to allow error responses to include potentially
+ sensitive private information (such as full responses
+ from the OAuth 2.0 server) that might aid in debugging
+ problems. Should be set to "NO" in production.
+
+
+EXCHANGE KYC KYCAID OPTIONS
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following options must be in the section "[kyc-provider-XXX]" sections with "LOGIC = kycaid".
+
+
+KYC_KYCAID_VALIDITY
+ Duration (e.g. "12 months") of the validity of the performed KYC check. Can be "forever".
+
+KYC_KYCAID_AUTH_TOKEN
+ Authentication token to access the KYC service.
+
+KYC_KYCAID_FORM_ID
+ ID that specifies the form to use for the KYC process.
+
+KYC_KYCAID_POST_URL
+ URL to which the exchange will redirect the client's browser after successful authorization/login for the KYC process.
+
+
+EXCHANGE KYC PERSONA OPTIONS
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following options must be in the section "[kyc-provider-XXX]" sections with "LOGIC = persona".
+
+
+KYC_PERSONA_VALIDITY
+ Duration (e.g. "12 months") of the validity of the performed KYC check. Can be "forever".
+
+KYC_PERSONA_AUTH_TOKEN
+ Authentication token to access the KYC service.
+
+KYC_PERSONA_SALT
+ Salt value to use for request idempotency. Optional, generated at random per process if not given.
+
+KYC_PERSONA_SUBDOMAIN
+ Subdomain to use under Persona.
+
+KYC_PERSONA_CONVERTER_HELPER
+ Helper to convert JSON with KYC data returned by Persona into GNU Taler internal format. Should probably always be set to "taler-exchange-kyc-persona-converter.sh".
+
+KYC_PERSONA_POST_URL
+ URL to which the exchange will redirect the client's browser after successful authorization/login for the KYC process.
+
+KYC_PERSONA_TEMPLATE_ID
+ ID of the Persona template to use.
+
+EXCHANGE KYC PERSONA GLOBAL OPTIONS
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following option must be in the section "[kyclogic-persona]".
+
+
+WEBHOOK_AUTH_TOKEN
+ Authentication token Persona must supply to our webhook. This is an optional setting.
+
+
+EXCHANGE EXTENSIONS OPTIONS
+---------------------------
+
+The functionality of the exchange can be extended by extensions. Those are
+shared libraries which implement the extension-API of the exchange and are
+located under ``$LIBDIR``, starting with prefix ``libtaler_extension_``. Each
+extension can be enabled by adding a dedicated section
+"[exchange-extension-<extensionname>]" and the following option:
+
+ENABLED
+ If set to ``YES`` the extension ``<extensionsname>`` is enabled. Extension-specific
+ options might be set in the same section.
+
+
+EXCHANGE EXTENSION FOR AGE RESTRICTION
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The extension for age restriction support can be enabled by adding a section
+"[exchange-extension-age_restriction]" with the following options:
+
+ENABLE
+ Must be set to ``YES`` in order to activate the extension.
+
+AGE_GROUPS
+ A colon-seperated string of increasing non-negative integers, defining the
+ buckets of age groups supported by the exchange. Each integer marks the
+ beginning of the next age group. The zero'th age group implicitly starts
+ with 0. For example, the string "10:18" would define three age groups:
+
+ 1. Group 0: ages 0 through 9 (including)
+ 2. Group 1: ages 10 through 17 (including)
+ 3. Group 2: ages 18 and above
+
+ If not provided, the default value is "8:10:12:14:16:18:21".
+
+**Note**: Age restriction is bound to specific denominations and must be
+enabled for each selected denomination in the corresponding section by adding
+the option ``AGE_RESTRICTED = YES``, see `EXCHANGE COIN OPTIONS`_. However, the
+age groups are defined globally for all denominations.
+
+
+
EXCHANGE OFFLINE SIGNING OPTIONS
--------------------------------
The following options must be in the section "[exchange-offline]".
MASTER_PRIV_FILE
- Where to store the offline private key of the exchange.
+ Location of the master private key on disk. Only used by tools that
+ can be run offline (as the master key is for offline signing).
Mandatory.
SECM_TOFU_FILE
@@ -230,6 +460,34 @@ Note that the **taler-exchange-secmod-rsa** also evaluates the ``[coin_*]``
configuration sections described below.
+EXCHANGE CS CRYPTO HELPER OPTIONS
+---------------------------------
+
+The following options must be in the section "[taler-exchange-secmod-cs]".
+
+LOOKAHEAD_SIGN
+ How long do we generate denomination and signing keys ahead of time?
+
+OVERLAP_DURATION
+ How much should validity periods for coins overlap?
+ Should be long enough to avoid problems with
+ wallets picking one key and then due to network latency
+ another key being valid. The ``DURATION_WITHDRAW`` period
+ must be longer than this value.
+
+SM_PRIV_KEY
+ Where should the security module store its long-term private key?
+
+KEY_DIR
+ Where should the security module store the private keys it manages?
+
+UNIXPATH
+ On which path should the security module listen for signing requests?
+
+Note that the **taler-exchange-secmod-cs** also evaluates the ``[coin_*]``
+configuration sections described below.
+
+
EXCHANGE EDDSA CRYPTO HELPER OPTIONS
------------------------------------
@@ -271,6 +529,14 @@ IDLE_RESERVE_EXPIRATION_TIME
LEGAL_RESERVE_EXPIRATION_TIME
After what time do we forget about (drained) reserves during garbage collection?
+AGGREGATOR_SHIFT
+ Delay between a deposit being eligible for aggregation and
+ the aggregator actually triggering.
+
+DEFAULT_PURSE_LIMIT
+ Number of concurrent purses that a reserve may have active
+ if it is paid to be opened for a year.
+
EXCHANGE POSTGRES BACKEND DATABASE OPTIONS
------------------------------------------
@@ -373,8 +639,19 @@ FEE_REFUND
What fee is charged for refunds? When a coin is refunded, the deposit
fee is returned. Instead, the refund fee is charged to the customer.
+CIPHER
+ What cryptosystem should be used? Must be set to either "CS" or "RSA".
+ The respective crypto-helper will then generate the keys for this
+ denomination.
+
RSA_KEYSIZE
- What is the RSA keysize modulos (in bits)?
+ What is the RSA keysize modulos (in bits)? Only used if "CIPHER=RSA".
+
+AGE_RESTRICTED
+ Setting this option to ``YES`` marks the denomination as age restricted
+ (default is ``NO``). For this option to be accepted the extension for age
+ restriction MUST be enabled (see `EXCHANGE EXTENSION FOR AGE RESTRICTION`_).
+
MERCHANT OPTIONS
----------------
@@ -385,9 +662,24 @@ merchant backend.
DB
Plugin to use for the database, e.g._“postgres”.
+SERVE
+ Should the HTTP server listen on a UNIX domain socket (set option to "unix") or on a TCP socket (set option to "tcp")?
+
+BASE_URL
+ Which base URL should the merchant backend assume for itself in the protocol. Optional. If not given, the base URL will be constructed from X-Forwarded-Host, X-Forwarded-Port and X-Forwarded-Prefix headers that a reverse-proxy should be setting.
+
+UNIXPATH
+ Path to listen on if we "SERVE" is set to "unix".
+
+UNIXPATH_MODE
+ Access permission mask to use for the "UNIXPATH".
+
PORT
Port on which the HTTP server listens, e.g. 8080.
+BIND_TO
+ Hostname to which the merchant HTTP server should be bound to, e.g. "localhost".
+
LEGAL_PRESERVATION
How long do we keep data in the database for tax audits after the
transaction has completed? Default is 10 years.
@@ -436,25 +728,8 @@ CURRENCY
The entire section is ignored if the currency does not match the currency
we use, which must be given in the ``[taler]`` section.
-KNOWN AUDITORS (for merchants)
-------------------------------
-
-The merchant configuration can include a list of known exchanges if the
-merchant wants to specify that certain auditors are explicitly trusted.
-For each trusted exchange, a section “[merchant-auditor-$NAME]” must exist, where
-``$NAME`` is a merchant-given name for the auditor. The following options
-must be given in each “[merchant-auditor-$NAME]” section.
-
-AUDITOR_BASE_URL
- Base URL of the auditor, e.g. “https://auditor.demo.taler.net/”
-
-AUDITOR_KEY
- Crockford Base32 encoded auditor public key.
-
-CURRENCY
- Name of the currency for which this auditor is trusted, e.g. “KUDOS”
- The entire section is ignored if the currency does not match the currency
- we use, which must be given in the ``[taler]`` section.
+DISABLED
+ Set to YES to disable this exchange. Optional option, defaults to NO.
AUDITOR OPTIONS
@@ -476,6 +751,23 @@ PUBLIC_KEY
BASE_URL
Base URL of the auditor, e.g. “https://auditor.demo.taler.net/”
+SERVE
+ Should the HTTP server listen on a UNIX domain socket (set option to "unix") or on a TCP socket (set option to "tcp")?
+
+UNIXPATH
+ Path to listen on if we "SERVE" is set to "unix".
+
+UNIXPATH_MODE
+ Access permission mask to use for the "UNIXPATH".
+
+PORT
+ Port on which the HTTP server listens, e.g. 8080.
+
+BIND_TO
+ Hostname to which the merchant HTTP server should be bound to, e.g. "localhost".
+
+
+
AUDITOR POSTGRES BACKEND DATABASE OPTIONS
-----------------------------------------
@@ -488,6 +780,63 @@ CONFIG
"taler" database. Testcases use “talercheck”.
+Bank Options
+------------
+
+The following options must be in section "[bank]" for the taler-fakebank-run(1) command. They are not used by the exchange or LibEuFin!
+
+HTTP_PORT
+ On which TCP port should the (fake)bank offer its REST API.
+RAM_LIMIT
+ This gives the number of transactions to keep in memory. Older transactions will be overwritten and history requests for overwritten transactions will fail.
+
+
+Taler-mdb Options
+-----------------
+
+Taler-mdb is a component to run GNU Taler as a payment system on
+vending machines using the multi-drop bus protocol. These options
+are thus not useful for most users. Note that right now, the
+cancel button is hard-coded to be using GPIO pin 23.
+
+ADVERTISEMENT_COMMAND
+ Program to run while not vending, possibly useful to show advertisements on the screen (optional).
+ESSID
+ ESSID to advertise to wallets for use as an open WiFi to make payments (optional).
+FULFILLMENT_MSG
+ Message shown to users by their wallets upon successful payment. If "${PRODUCT_DESCRIPTION}" appears in the message, it will be replaced with the description of the product that was sold.
+BACKEND_BASE_URL
+ Base URL (possibly including instance) for the Taler merchant backend used to process payments.
+BACKEND_AUTHORIZATION
+ Full HTTP "Authorization" header (usually with a Bearer token) to be send to the merchant backend for authorization of requests. Mandatory.
+FRAMEBUFFER_BACKLIGHT
+ Name of the file used to control brightness of the display. Optional. Defaults to "/sys/class/backlight/soc:backlight/brightness" if not given.
+FRAMEBUFFER_DEVICE
+ Name of the framebuffer device to use. Defaults to "/dev/fb1" if not given.
+UART_DEVICE
+ Name of the UART device to use. Defaults to "/dev/ttyAMA0" if not given.
+FAIL_COMMAND
+ Command to run to display a failure to the user. If not given, errors will not be properly shown.
+
+Each products being sold must be configured in a section where the name starts with "product-".
+In these sections, the options that must be provided are:
+
+NUMBER
+ Number identifying the slot in the vending machine that corresponds to this product.
+INSTANCE
+ Instance to use for the payment. Optional. If not given, the BACKEND_BASE_URL from "[taler-mdb]" will be used.
+BACKEND_AUTHORIZATION
+ Full HTTP "Authorization" header (usually with a Bearer token) to be send to the merchant backend for authorization of requests. Optional, will use global BACKEND_AUTHORIZATION setting from "[taler-mdb]" if missing.
+DESCRIPTION
+ Human-readable description of the product. Use "empty" if the product is known to be sold out (only effective if selling out is enabled via command-line).
+PRICE
+ Actual price of the product, as a Taler amount ("$CURRENCY:$VALUE.$FRACTION").
+KEY
+ Key used to select the product from the console during testing. Optional.
+THUMBNAIL
+ Name of a filename with a preview image of the product to be given to the wallet. Optional. Only ".png", ".jpg", ".jpeg" and ".svg" are supported at this time.
+
+
SEE ALSO
========
diff --git a/merchant-benchmark.conf b/merchant-benchmark.conf
index 3702302d..5ce84574 100644
--- a/merchant-benchmark.conf
+++ b/merchant-benchmark.conf
@@ -51,7 +51,7 @@ CURRENCY = EUR
# The account name MUST be 'Exchange'
PAYTO_URI = payto://x-taler-bank/localhost/Exchange
WIRE_RESPONSE = ${TALER_CONFIG_HOME}/exchange/account.json
-WIRE_GATEWAY_URL = http://localhost:8082/taler-wire-gateway/Exchange/
+WIRE_GATEWAY_URL = http://localhost:8082/accounts/Exchange/taler-wire-gateway/
WIRE_GATEWAY_AUTH_METHOD = basic
USERNAME = Exchange
# The password MUST be 'x'
@@ -120,4 +120,3 @@ fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
rsa_keysize = 1024
-
diff --git a/merchant-spec/public-orders-get.ts b/merchant-spec/public-orders-get.ts
index 4a98aab4..8a5df17e 100644
--- a/merchant-spec/public-orders-get.ts
+++ b/merchant-spec/public-orders-get.ts
@@ -122,7 +122,7 @@ function respForbidden(req: Req): Resp {
}
function respAlreadyPaid(req: Req, alreadyPaidOrd: MerchantOrderInfo): Resp {
- // This could be called with an empty fulfillment URL, but that doens't
+ // This could be called with an empty fulfillment URL, but that doesn't
// really make sense for the client's perspective.
if (req.accept === "html") {
return {
diff --git a/orphaned/README b/orphaned/README
new file mode 100644
index 00000000..4035e4b4
--- /dev/null
+++ b/orphaned/README
@@ -0,0 +1,2 @@
+This document contains documentation that we currently don't link anywhere,
+but that we might still want to salvage sometime.
diff --git a/taler-mcig.rst b/orphaned/taler-mcig.rst
index d1247aee..1950f4af 100644
--- a/taler-mcig.rst
+++ b/orphaned/taler-mcig.rst
@@ -81,7 +81,7 @@ The contract includes:
- (optional) information which details are *forgettable*;
- (optional) a *claim token* that the customer can use later;
- (optional) information on the *refund deadline*;
-- (optional) information on the the *auto-refund period* (how long does the wallet check for refunds without user prompting for it).
+- (optional) information on the *auto-refund period* (how long does the wallet check for refunds without user prompting for it).
If the customer does nothing (timeout / the contract expires),
the merchant backend automatically *unlocks* the product(s),
@@ -294,7 +294,7 @@ M: :http:post:`/management/instances`
// InstanceConfigurationMessage
{
- "payto_uris": ["payto://iban/CH9300762011623852957"],
+ "accounts": [{"payto_uri":"payto://iban/CH9300762011623852957"}],
"id": "default",
"name": "Pretty Pianos",
"auth":
@@ -315,7 +315,7 @@ The fictitious store, Pretty Pianos, has only two products:
- pianos (physical good);
- *Beethoven Sonatas* (sheet music PDF files, digital good).
-M: :http:post:`/instances/default/private/products`
+M: POST ``/instances/default/private/products``
.. code-block:: javascript
@@ -338,7 +338,7 @@ field's list value.
This means the ``image`` value is *marked as forgettable*.
This will come into play later (see below).
-M: :http:post:`/instances/default/private/products`
+M: POST ``/instances/default/private/products``
.. code-block:: javascript
@@ -384,7 +384,7 @@ they need never pay again for it.
When the customer clicks on the product's "buy" button,
you first POST to ``/private/orders`` to create an order:
-M: :http:post:`/instances/default/private/orders`
+M: POST ``/instances/default/private/orders``
.. code-block:: javascript
@@ -425,7 +425,7 @@ Notes:
Now that there is an order in the system, the wallet *claims* the order.
-W: :http:post:`/orders/G93420934823/claim`
+W: POST ``/orders/G93420934823/claim``
.. code-block:: javascript
@@ -508,7 +508,7 @@ for the offer to time out).
The customer accepts the contract:
-W: :http:post:`/orders/G93420934823/pay`
+W: POST ``/orders/G93420934823/pay``
.. code-block:: javascript
diff --git a/taler-nfc-guide.rst b/orphaned/taler-nfc-guide.rst
index 1b3cfb18..d025d347 100644
--- a/taler-nfc-guide.rst
+++ b/orphaned/taler-nfc-guide.rst
@@ -22,7 +22,8 @@ Background: Payment Processing with GNU Taler
The following steps show a simple payment process with GNU Taler. Examples are
written in `Bash <https://www.gnu.org/software/bash/>`_ syntax,
using `curl <https://curl.haxx.se/docs/manpage.html>`_ to make HTTP(S) requests.
-
+They make use of the :http:post:`[/instances/$INSTANCE]/private/orders`
+and :http:get:`[/instances/$INSTANCE]/private/orders` endpoints.
1. The merchant creates an *order*, which contains the details of the payment
and the product/service that the customer will receive.
@@ -45,7 +46,7 @@ using `curl <https://curl.haxx.se/docs/manpage.html>`_ to make HTTP(S) requests.
can be opened, and give a warning if it is detected that the devices does not have Internet
connectivity.
- The following :http:post:`/private/orders` request to the merchant backend creates a
+ The following POST ``/private/orders`` request to the merchant backend creates a
simple order:
.. code-block:: console
@@ -69,7 +70,7 @@ using `curl <https://curl.haxx.se/docs/manpage.html>`_ to make HTTP(S) requests.
}
2. The merchant checks the payment status of the order using
- :http:get:`/private/orders/$ORDER_ID`:
+ GET ``/private/orders/$ORDER_ID``:
.. code-block:: console
@@ -92,7 +93,7 @@ using `curl <https://curl.haxx.se/docs/manpage.html>`_ to make HTTP(S) requests.
* by manually entering it in the command-line wallet
* **via NFC** (explained in this guide)
- The details of ``taler://`` URIs are specified :ref:`here <taler-uri-scheme>`.
+ The details of ``taler://`` URIs are specified in `LSD 0006 <https://lsd.gnunet.org/lsd0006/>`_.
3. The wallet processes the ``taler://pay/`` URI. In this example, we use the
command-line wallet:
@@ -135,7 +136,8 @@ using `curl <https://curl.haxx.se/docs/manpage.html>`_ to make HTTP(S) requests.
before responding with the fulfillment page.
For in-store payments, the merchant must periodically check the payment status.
- Instead of polling in a busy loop, the ``timeout_ms`` parameter of :http:get:`/private/orders/$ORDER_ID`
+ Instead of polling in a busy loop, the ``timeout_ms`` parameter
+ of GET ``/private/orders/$ORDER_ID``
should be used.
@@ -229,8 +231,8 @@ to dereference the ``taler://pay`` URI from the example above:
# success response with no data
m<-w 9000
-(Note that this process works analogously for communication between a bank/ATM
-terminal or "tipping provider".)
+(Note that this process works analogously for communication with a bank/ATM
+terminal.)
Request tunneling
diff --git a/python-guidelines.rst b/python-guidelines.rst
index f08b563f..8a644ced 100644
--- a/python-guidelines.rst
+++ b/python-guidelines.rst
@@ -47,7 +47,7 @@ Formatting
----------
* We follow `pep8 <https://www.python.org/dev/peps/pep-0008/>`__.
-* Code should be auto-formatted wich `black <https://github.com/psf/black>`__.
+* Code should be auto-formatted with `black <https://github.com/psf/black>`__.
Distro Packaging
diff --git a/screenshots/create_orders.png b/screenshots/create_orders.png
new file mode 100644
index 00000000..74814c72
--- /dev/null
+++ b/screenshots/create_orders.png
Binary files differ
diff --git a/screenshots/cta-accept-tos-android-0.png b/screenshots/cta-accept-tos-android-0.png
new file mode 100644
index 00000000..c9537071
--- /dev/null
+++ b/screenshots/cta-accept-tos-android-0.png
Binary files differ
diff --git a/screenshots/cta-accept-tos-android-latest.png b/screenshots/cta-accept-tos-android-latest.png
new file mode 120000
index 00000000..89544b02
--- /dev/null
+++ b/screenshots/cta-accept-tos-android-latest.png
@@ -0,0 +1 @@
+cta-accept-tos-android-0.png \ No newline at end of file
diff --git a/screenshots/cta-accept-tos-chrome-0.png b/screenshots/cta-accept-tos-chrome-0.png
new file mode 100644
index 00000000..998ef33d
--- /dev/null
+++ b/screenshots/cta-accept-tos-chrome-0.png
Binary files differ
diff --git a/screenshots/cta-accept-tos-chrome-latest.png b/screenshots/cta-accept-tos-chrome-latest.png
new file mode 120000
index 00000000..411020c1
--- /dev/null
+++ b/screenshots/cta-accept-tos-chrome-latest.png
@@ -0,0 +1 @@
+cta-accept-tos-chrome-0.png \ No newline at end of file
diff --git a/screenshots/cta-accept-tos-firefox-0.png b/screenshots/cta-accept-tos-firefox-0.png
new file mode 100644
index 00000000..6809d775
--- /dev/null
+++ b/screenshots/cta-accept-tos-firefox-0.png
Binary files differ
diff --git a/screenshots/cta-accept-tos-firefox-latest.png b/screenshots/cta-accept-tos-firefox-latest.png
new file mode 120000
index 00000000..f1b6f069
--- /dev/null
+++ b/screenshots/cta-accept-tos-firefox-latest.png
@@ -0,0 +1 @@
+cta-accept-tos-firefox-0.png \ No newline at end of file
diff --git a/screenshots/cta-accept-tos-ios-0.png b/screenshots/cta-accept-tos-ios-0.png
new file mode 100644
index 00000000..b71d7dcf
--- /dev/null
+++ b/screenshots/cta-accept-tos-ios-0.png
Binary files differ
diff --git a/screenshots/cta-accept-tos-ios-latest.png b/screenshots/cta-accept-tos-ios-latest.png
new file mode 120000
index 00000000..091a79a1
--- /dev/null
+++ b/screenshots/cta-accept-tos-ios-latest.png
@@ -0,0 +1 @@
+cta-accept-tos-ios-0.png \ No newline at end of file
diff --git a/screenshots/cta-balance-list-android-0.png b/screenshots/cta-balance-list-android-0.png
new file mode 100644
index 00000000..f87919f8
--- /dev/null
+++ b/screenshots/cta-balance-list-android-0.png
Binary files differ
diff --git a/screenshots/cta-balance-list-android-latest.png b/screenshots/cta-balance-list-android-latest.png
new file mode 120000
index 00000000..90d09afe
--- /dev/null
+++ b/screenshots/cta-balance-list-android-latest.png
@@ -0,0 +1 @@
+cta-balance-list-android-0.png \ No newline at end of file
diff --git a/screenshots/cta-balance-list-firefox-0.png b/screenshots/cta-balance-list-firefox-0.png
new file mode 100644
index 00000000..6a4fcb12
--- /dev/null
+++ b/screenshots/cta-balance-list-firefox-0.png
Binary files differ
diff --git a/screenshots/cta-balance-list-firefox-latest.png b/screenshots/cta-balance-list-firefox-latest.png
new file mode 120000
index 00000000..e5874826
--- /dev/null
+++ b/screenshots/cta-balance-list-firefox-latest.png
@@ -0,0 +1 @@
+cta-balance-list-firefox-0.png \ No newline at end of file
diff --git a/screenshots/cta-balance-list-ios-0.png b/screenshots/cta-balance-list-ios-0.png
new file mode 100644
index 00000000..4afe8c5c
--- /dev/null
+++ b/screenshots/cta-balance-list-ios-0.png
Binary files differ
diff --git a/screenshots/cta-balance-list-ios-latest.png b/screenshots/cta-balance-list-ios-latest.png
new file mode 120000
index 00000000..068683fa
--- /dev/null
+++ b/screenshots/cta-balance-list-ios-latest.png
@@ -0,0 +1 @@
+cta-balance-list-ios-0.png \ No newline at end of file
diff --git a/screenshots/cta-deposit-1-ios-0.png b/screenshots/cta-deposit-1-ios-0.png
new file mode 100644
index 00000000..6cf30dde
--- /dev/null
+++ b/screenshots/cta-deposit-1-ios-0.png
Binary files differ
diff --git a/screenshots/cta-deposit-1-ios-latest.png b/screenshots/cta-deposit-1-ios-latest.png
new file mode 120000
index 00000000..a3a21c74
--- /dev/null
+++ b/screenshots/cta-deposit-1-ios-latest.png
@@ -0,0 +1 @@
+cta-deposit-1-ios-0.png \ No newline at end of file
diff --git a/screenshots/cta-deposit-2-ios-0.png b/screenshots/cta-deposit-2-ios-0.png
new file mode 100644
index 00000000..49007f6c
--- /dev/null
+++ b/screenshots/cta-deposit-2-ios-0.png
Binary files differ
diff --git a/screenshots/cta-deposit-2-ios-latest.png b/screenshots/cta-deposit-2-ios-latest.png
new file mode 120000
index 00000000..5dd80393
--- /dev/null
+++ b/screenshots/cta-deposit-2-ios-latest.png
@@ -0,0 +1 @@
+cta-deposit-2-ios-0.png \ No newline at end of file
diff --git a/screenshots/cta-deposit-android-0.png b/screenshots/cta-deposit-android-0.png
new file mode 100644
index 00000000..74435360
--- /dev/null
+++ b/screenshots/cta-deposit-android-0.png
Binary files differ
diff --git a/screenshots/cta-deposit-android-latest.png b/screenshots/cta-deposit-android-latest.png
new file mode 120000
index 00000000..53a323c3
--- /dev/null
+++ b/screenshots/cta-deposit-android-latest.png
@@ -0,0 +1 @@
+cta-deposit-android-0.png \ No newline at end of file
diff --git a/screenshots/cta-deposit-firefox-0.png b/screenshots/cta-deposit-firefox-0.png
new file mode 100644
index 00000000..e78538c7
--- /dev/null
+++ b/screenshots/cta-deposit-firefox-0.png
Binary files differ
diff --git a/screenshots/cta-deposit-firefox-latest.png b/screenshots/cta-deposit-firefox-latest.png
new file mode 120000
index 00000000..93e5beca
--- /dev/null
+++ b/screenshots/cta-deposit-firefox-latest.png
@@ -0,0 +1 @@
+cta-deposit-firefox-0.png \ No newline at end of file
diff --git a/screenshots/cta-payment-android-0.png b/screenshots/cta-payment-android-0.png
new file mode 100644
index 00000000..d518c922
--- /dev/null
+++ b/screenshots/cta-payment-android-0.png
Binary files differ
diff --git a/screenshots/cta-payment-android-latest.png b/screenshots/cta-payment-android-latest.png
new file mode 120000
index 00000000..b858e45f
--- /dev/null
+++ b/screenshots/cta-payment-android-latest.png
@@ -0,0 +1 @@
+cta-payment-android-0.png \ No newline at end of file
diff --git a/screenshots/cta-payment-chrome-0.png b/screenshots/cta-payment-chrome-0.png
new file mode 100644
index 00000000..51b2afe3
--- /dev/null
+++ b/screenshots/cta-payment-chrome-0.png
Binary files differ
diff --git a/screenshots/cta-payment-chrome-latest.png b/screenshots/cta-payment-chrome-latest.png
new file mode 120000
index 00000000..1c63e828
--- /dev/null
+++ b/screenshots/cta-payment-chrome-latest.png
@@ -0,0 +1 @@
+cta-payment-chrome-0.png \ No newline at end of file
diff --git a/screenshots/cta-payment-firefox-0.png b/screenshots/cta-payment-firefox-0.png
new file mode 100644
index 00000000..c9d01380
--- /dev/null
+++ b/screenshots/cta-payment-firefox-0.png
Binary files differ
diff --git a/screenshots/cta-payment-firefox-latest.png b/screenshots/cta-payment-firefox-latest.png
new file mode 120000
index 00000000..26b0f16e
--- /dev/null
+++ b/screenshots/cta-payment-firefox-latest.png
@@ -0,0 +1 @@
+cta-payment-firefox-0.png \ No newline at end of file
diff --git a/screenshots/cta-payment-ios-0.png b/screenshots/cta-payment-ios-0.png
new file mode 100644
index 00000000..ad7cb8f0
--- /dev/null
+++ b/screenshots/cta-payment-ios-0.png
Binary files differ
diff --git a/screenshots/cta-payment-ios-latest.png b/screenshots/cta-payment-ios-latest.png
new file mode 120000
index 00000000..130b47c8
--- /dev/null
+++ b/screenshots/cta-payment-ios-latest.png
@@ -0,0 +1 @@
+cta-payment-ios-0.png \ No newline at end of file
diff --git a/screenshots/cta-payment-paid-android-0.png b/screenshots/cta-payment-paid-android-0.png
new file mode 100644
index 00000000..51a412c7
--- /dev/null
+++ b/screenshots/cta-payment-paid-android-0.png
Binary files differ
diff --git a/screenshots/cta-payment-paid-android-latest.png b/screenshots/cta-payment-paid-android-latest.png
new file mode 120000
index 00000000..8aabd17e
--- /dev/null
+++ b/screenshots/cta-payment-paid-android-latest.png
@@ -0,0 +1 @@
+cta-payment-paid-android-0.png \ No newline at end of file
diff --git a/screenshots/cta-payment-paid-chrome-0.png b/screenshots/cta-payment-paid-chrome-0.png
new file mode 100644
index 00000000..d6afcf6f
--- /dev/null
+++ b/screenshots/cta-payment-paid-chrome-0.png
Binary files differ
diff --git a/screenshots/cta-payment-paid-chrome-latest.png b/screenshots/cta-payment-paid-chrome-latest.png
new file mode 120000
index 00000000..575c3d59
--- /dev/null
+++ b/screenshots/cta-payment-paid-chrome-latest.png
@@ -0,0 +1 @@
+cta-payment-paid-chrome-0.png \ No newline at end of file
diff --git a/screenshots/cta-payment-paid-firefox-0.png b/screenshots/cta-payment-paid-firefox-0.png
new file mode 100644
index 00000000..f67e2af3
--- /dev/null
+++ b/screenshots/cta-payment-paid-firefox-0.png
Binary files differ
diff --git a/screenshots/cta-payment-paid-firefox-latest.png b/screenshots/cta-payment-paid-firefox-latest.png
new file mode 120000
index 00000000..22dd4530
--- /dev/null
+++ b/screenshots/cta-payment-paid-firefox-latest.png
@@ -0,0 +1 @@
+cta-payment-paid-firefox-0.png \ No newline at end of file
diff --git a/screenshots/cta-payment-paid-ios-0.png b/screenshots/cta-payment-paid-ios-0.png
new file mode 100644
index 00000000..60d92221
--- /dev/null
+++ b/screenshots/cta-payment-paid-ios-0.png
Binary files differ
diff --git a/screenshots/cta-payment-paid-ios-latest.png b/screenshots/cta-payment-paid-ios-latest.png
new file mode 120000
index 00000000..e03f4750
--- /dev/null
+++ b/screenshots/cta-payment-paid-ios-latest.png
@@ -0,0 +1 @@
+cta-payment-paid-ios-0.png \ No newline at end of file
diff --git a/screenshots/cta-peer-pull-initiate-android-0.png b/screenshots/cta-peer-pull-initiate-android-0.png
new file mode 100644
index 00000000..9be8abdf
--- /dev/null
+++ b/screenshots/cta-peer-pull-initiate-android-0.png
Binary files differ
diff --git a/screenshots/cta-peer-pull-initiate-android-latest.png b/screenshots/cta-peer-pull-initiate-android-latest.png
new file mode 120000
index 00000000..eeb4d8c9
--- /dev/null
+++ b/screenshots/cta-peer-pull-initiate-android-latest.png
@@ -0,0 +1 @@
+cta-peer-pull-initiate-android-0.png \ No newline at end of file
diff --git a/screenshots/cta-peer-pull-initiate-firefox-0.png b/screenshots/cta-peer-pull-initiate-firefox-0.png
new file mode 100644
index 00000000..0d7c1b31
--- /dev/null
+++ b/screenshots/cta-peer-pull-initiate-firefox-0.png
Binary files differ
diff --git a/screenshots/cta-peer-pull-initiate-firefox-latest.png b/screenshots/cta-peer-pull-initiate-firefox-latest.png
new file mode 120000
index 00000000..74339ee9
--- /dev/null
+++ b/screenshots/cta-peer-pull-initiate-firefox-latest.png
@@ -0,0 +1 @@
+cta-peer-pull-initiate-firefox-0.png \ No newline at end of file
diff --git a/screenshots/cta-peer-pull-initiate-ios-0.png b/screenshots/cta-peer-pull-initiate-ios-0.png
new file mode 100644
index 00000000..421cae8c
--- /dev/null
+++ b/screenshots/cta-peer-pull-initiate-ios-0.png
Binary files differ
diff --git a/screenshots/cta-peer-pull-initiate-ios-latest.png b/screenshots/cta-peer-pull-initiate-ios-latest.png
new file mode 120000
index 00000000..e083752f
--- /dev/null
+++ b/screenshots/cta-peer-pull-initiate-ios-latest.png
@@ -0,0 +1 @@
+cta-peer-pull-initiate-ios-0.png \ No newline at end of file
diff --git a/screenshots/cta-peer-push-initiate-android-0.png b/screenshots/cta-peer-push-initiate-android-0.png
new file mode 100644
index 00000000..8ee0ef7d
--- /dev/null
+++ b/screenshots/cta-peer-push-initiate-android-0.png
Binary files differ
diff --git a/screenshots/cta-peer-push-initiate-android-latest.png b/screenshots/cta-peer-push-initiate-android-latest.png
new file mode 120000
index 00000000..ee8bd57a
--- /dev/null
+++ b/screenshots/cta-peer-push-initiate-android-latest.png
@@ -0,0 +1 @@
+cta-peer-push-initiate-android-0.png \ No newline at end of file
diff --git a/screenshots/cta-peer-push-initiate-firefox-0.png b/screenshots/cta-peer-push-initiate-firefox-0.png
new file mode 100644
index 00000000..f566b0cb
--- /dev/null
+++ b/screenshots/cta-peer-push-initiate-firefox-0.png
Binary files differ
diff --git a/screenshots/cta-peer-push-initiate-firefox-latest.png b/screenshots/cta-peer-push-initiate-firefox-latest.png
new file mode 120000
index 00000000..98a59294
--- /dev/null
+++ b/screenshots/cta-peer-push-initiate-firefox-latest.png
@@ -0,0 +1 @@
+cta-peer-push-initiate-firefox-0.png \ No newline at end of file
diff --git a/screenshots/cta-peer-push-initiate-ios-0.png b/screenshots/cta-peer-push-initiate-ios-0.png
new file mode 100644
index 00000000..a574c880
--- /dev/null
+++ b/screenshots/cta-peer-push-initiate-ios-0.png
Binary files differ
diff --git a/screenshots/cta-peer-push-initiate-ios-latest.png b/screenshots/cta-peer-push-initiate-ios-latest.png
new file mode 120000
index 00000000..f42c0924
--- /dev/null
+++ b/screenshots/cta-peer-push-initiate-ios-latest.png
@@ -0,0 +1 @@
+cta-peer-push-initiate-ios-0.png \ No newline at end of file
diff --git a/screenshots/cta-transaction-list-android-0.png b/screenshots/cta-transaction-list-android-0.png
new file mode 100644
index 00000000..e9309a83
--- /dev/null
+++ b/screenshots/cta-transaction-list-android-0.png
Binary files differ
diff --git a/screenshots/cta-transaction-list-android-latest.png b/screenshots/cta-transaction-list-android-latest.png
new file mode 120000
index 00000000..9bf9ffa8
--- /dev/null
+++ b/screenshots/cta-transaction-list-android-latest.png
@@ -0,0 +1 @@
+cta-transaction-list-android-0.png \ No newline at end of file
diff --git a/screenshots/cta-transaction-list-firefox-0.png b/screenshots/cta-transaction-list-firefox-0.png
new file mode 100644
index 00000000..d2d12ca8
--- /dev/null
+++ b/screenshots/cta-transaction-list-firefox-0.png
Binary files differ
diff --git a/screenshots/cta-transaction-list-firefox-latest.png b/screenshots/cta-transaction-list-firefox-latest.png
new file mode 120000
index 00000000..330e9024
--- /dev/null
+++ b/screenshots/cta-transaction-list-firefox-latest.png
@@ -0,0 +1 @@
+cta-transaction-list-firefox-0.png \ No newline at end of file
diff --git a/screenshots/cta-transaction-list-ios-0.png b/screenshots/cta-transaction-list-ios-0.png
new file mode 100644
index 00000000..6180c2c5
--- /dev/null
+++ b/screenshots/cta-transaction-list-ios-0.png
Binary files differ
diff --git a/screenshots/cta-transaction-list-ios-latest.png b/screenshots/cta-transaction-list-ios-latest.png
new file mode 120000
index 00000000..3e8f3efc
--- /dev/null
+++ b/screenshots/cta-transaction-list-ios-latest.png
@@ -0,0 +1 @@
+cta-transaction-list-ios-0.png \ No newline at end of file
diff --git a/screenshots/cta-url-entry-android-0.png b/screenshots/cta-url-entry-android-0.png
new file mode 100644
index 00000000..18ed9bdf
--- /dev/null
+++ b/screenshots/cta-url-entry-android-0.png
Binary files differ
diff --git a/screenshots/cta-url-entry-android-latest.png b/screenshots/cta-url-entry-android-latest.png
new file mode 120000
index 00000000..2cd152f8
--- /dev/null
+++ b/screenshots/cta-url-entry-android-latest.png
@@ -0,0 +1 @@
+cta-url-entry-android-0.png \ No newline at end of file
diff --git a/screenshots/cta-url-entry-chrome-0.png b/screenshots/cta-url-entry-chrome-0.png
new file mode 100644
index 00000000..f1e296ad
--- /dev/null
+++ b/screenshots/cta-url-entry-chrome-0.png
Binary files differ
diff --git a/screenshots/cta-url-entry-chrome-latest.png b/screenshots/cta-url-entry-chrome-latest.png
new file mode 120000
index 00000000..5e6b9431
--- /dev/null
+++ b/screenshots/cta-url-entry-chrome-latest.png
@@ -0,0 +1 @@
+cta-url-entry-chrome-0.png \ No newline at end of file
diff --git a/screenshots/cta-url-entry-firefox-0.png b/screenshots/cta-url-entry-firefox-0.png
new file mode 100644
index 00000000..ba98a8e4
--- /dev/null
+++ b/screenshots/cta-url-entry-firefox-0.png
Binary files differ
diff --git a/screenshots/cta-url-entry-firefox-latest.png b/screenshots/cta-url-entry-firefox-latest.png
new file mode 120000
index 00000000..f24b6cb8
--- /dev/null
+++ b/screenshots/cta-url-entry-firefox-latest.png
@@ -0,0 +1 @@
+cta-url-entry-firefox-0.png \ No newline at end of file
diff --git a/screenshots/cta-wire-transfer-android-0.png b/screenshots/cta-wire-transfer-android-0.png
new file mode 100644
index 00000000..0393bf6e
--- /dev/null
+++ b/screenshots/cta-wire-transfer-android-0.png
Binary files differ
diff --git a/screenshots/cta-wire-transfer-android-latest.png b/screenshots/cta-wire-transfer-android-latest.png
new file mode 120000
index 00000000..f50509ba
--- /dev/null
+++ b/screenshots/cta-wire-transfer-android-latest.png
@@ -0,0 +1 @@
+cta-wire-transfer-android-0.png \ No newline at end of file
diff --git a/screenshots/cta-wire-transfer-chrome-0.png b/screenshots/cta-wire-transfer-chrome-0.png
new file mode 100644
index 00000000..c8e65494
--- /dev/null
+++ b/screenshots/cta-wire-transfer-chrome-0.png
Binary files differ
diff --git a/screenshots/cta-wire-transfer-chrome-latest.png b/screenshots/cta-wire-transfer-chrome-latest.png
new file mode 120000
index 00000000..617bcae5
--- /dev/null
+++ b/screenshots/cta-wire-transfer-chrome-latest.png
@@ -0,0 +1 @@
+cta-wire-transfer-chrome-0.png \ No newline at end of file
diff --git a/screenshots/cta-wire-transfer-firefox-0.png b/screenshots/cta-wire-transfer-firefox-0.png
new file mode 100644
index 00000000..7301cedc
--- /dev/null
+++ b/screenshots/cta-wire-transfer-firefox-0.png
Binary files differ
diff --git a/screenshots/cta-wire-transfer-firefox-latest.png b/screenshots/cta-wire-transfer-firefox-latest.png
new file mode 120000
index 00000000..202edda1
--- /dev/null
+++ b/screenshots/cta-wire-transfer-firefox-latest.png
@@ -0,0 +1 @@
+cta-wire-transfer-firefox-0.png \ No newline at end of file
diff --git a/screenshots/cta-wire-transfer-ios-0.png b/screenshots/cta-wire-transfer-ios-0.png
new file mode 100644
index 00000000..a7d37645
--- /dev/null
+++ b/screenshots/cta-wire-transfer-ios-0.png
Binary files differ
diff --git a/screenshots/cta-wire-transfer-ios-latest.png b/screenshots/cta-wire-transfer-ios-latest.png
new file mode 120000
index 00000000..29e7e4d9
--- /dev/null
+++ b/screenshots/cta-wire-transfer-ios-latest.png
@@ -0,0 +1 @@
+cta-wire-transfer-ios-0.png \ No newline at end of file
diff --git a/screenshots/cta-withdraw-android-0.png b/screenshots/cta-withdraw-android-0.png
new file mode 100644
index 00000000..9f7c99a6
--- /dev/null
+++ b/screenshots/cta-withdraw-android-0.png
Binary files differ
diff --git a/screenshots/cta-withdraw-android-latest.png b/screenshots/cta-withdraw-android-latest.png
new file mode 120000
index 00000000..eac8959d
--- /dev/null
+++ b/screenshots/cta-withdraw-android-latest.png
@@ -0,0 +1 @@
+cta-withdraw-android-0.png \ No newline at end of file
diff --git a/screenshots/cta-withdraw-chrome-0.png b/screenshots/cta-withdraw-chrome-0.png
new file mode 100644
index 00000000..7d200365
--- /dev/null
+++ b/screenshots/cta-withdraw-chrome-0.png
Binary files differ
diff --git a/screenshots/cta-withdraw-chrome-latest.png b/screenshots/cta-withdraw-chrome-latest.png
new file mode 120000
index 00000000..70518564
--- /dev/null
+++ b/screenshots/cta-withdraw-chrome-latest.png
@@ -0,0 +1 @@
+cta-withdraw-chrome-0.png \ No newline at end of file
diff --git a/screenshots/cta-withdraw-confirm-android-0.png b/screenshots/cta-withdraw-confirm-android-0.png
new file mode 100644
index 00000000..dbe4c7b1
--- /dev/null
+++ b/screenshots/cta-withdraw-confirm-android-0.png
Binary files differ
diff --git a/screenshots/cta-withdraw-confirm-chrome-0.png b/screenshots/cta-withdraw-confirm-chrome-0.png
new file mode 100644
index 00000000..56412acd
--- /dev/null
+++ b/screenshots/cta-withdraw-confirm-chrome-0.png
Binary files differ
diff --git a/screenshots/cta-withdraw-confirm-firefox-0.png b/screenshots/cta-withdraw-confirm-firefox-0.png
new file mode 100644
index 00000000..61d3c0a4
--- /dev/null
+++ b/screenshots/cta-withdraw-confirm-firefox-0.png
Binary files differ
diff --git a/screenshots/cta-withdraw-confirm-ios-0.png b/screenshots/cta-withdraw-confirm-ios-0.png
new file mode 100644
index 00000000..11dd9db0
--- /dev/null
+++ b/screenshots/cta-withdraw-confirm-ios-0.png
Binary files differ
diff --git a/screenshots/cta-withdraw-done-android-0.png b/screenshots/cta-withdraw-done-android-0.png
new file mode 100644
index 00000000..5860f280
--- /dev/null
+++ b/screenshots/cta-withdraw-done-android-0.png
Binary files differ
diff --git a/screenshots/cta-withdraw-done-android-latest.png b/screenshots/cta-withdraw-done-android-latest.png
new file mode 120000
index 00000000..7751f9d0
--- /dev/null
+++ b/screenshots/cta-withdraw-done-android-latest.png
@@ -0,0 +1 @@
+cta-withdraw-done-android-0.png \ No newline at end of file
diff --git a/screenshots/cta-withdraw-done-chrome-0.png b/screenshots/cta-withdraw-done-chrome-0.png
new file mode 100644
index 00000000..899ddd80
--- /dev/null
+++ b/screenshots/cta-withdraw-done-chrome-0.png
Binary files differ
diff --git a/screenshots/cta-withdraw-done-chrome-latest.png b/screenshots/cta-withdraw-done-chrome-latest.png
new file mode 120000
index 00000000..172c624f
--- /dev/null
+++ b/screenshots/cta-withdraw-done-chrome-latest.png
@@ -0,0 +1 @@
+cta-withdraw-done-chrome-0.png \ No newline at end of file
diff --git a/screenshots/cta-withdraw-done-firefox-0.png b/screenshots/cta-withdraw-done-firefox-0.png
new file mode 100644
index 00000000..3a3fc2f6
--- /dev/null
+++ b/screenshots/cta-withdraw-done-firefox-0.png
Binary files differ
diff --git a/screenshots/cta-withdraw-done-firefox-latest.png b/screenshots/cta-withdraw-done-firefox-latest.png
new file mode 120000
index 00000000..f707ff77
--- /dev/null
+++ b/screenshots/cta-withdraw-done-firefox-latest.png
@@ -0,0 +1 @@
+cta-withdraw-done-firefox-0.png \ No newline at end of file
diff --git a/screenshots/cta-withdraw-done-ios-0.png b/screenshots/cta-withdraw-done-ios-0.png
new file mode 100644
index 00000000..93561c5d
--- /dev/null
+++ b/screenshots/cta-withdraw-done-ios-0.png
Binary files differ
diff --git a/screenshots/cta-withdraw-done-ios-latest.png b/screenshots/cta-withdraw-done-ios-latest.png
new file mode 120000
index 00000000..26f90634
--- /dev/null
+++ b/screenshots/cta-withdraw-done-ios-latest.png
@@ -0,0 +1 @@
+cta-withdraw-done-ios-0.png \ No newline at end of file
diff --git a/screenshots/cta-withdraw-firefox-0.png b/screenshots/cta-withdraw-firefox-0.png
new file mode 100644
index 00000000..e75fb875
--- /dev/null
+++ b/screenshots/cta-withdraw-firefox-0.png
Binary files differ
diff --git a/screenshots/cta-withdraw-ios-0.png b/screenshots/cta-withdraw-ios-0.png
new file mode 100644
index 00000000..4db97e7c
--- /dev/null
+++ b/screenshots/cta-withdraw-ios-0.png
Binary files differ
diff --git a/screenshots/cta-withdraw-ios-latest.png b/screenshots/cta-withdraw-ios-latest.png
new file mode 120000
index 00000000..9c7d604b
--- /dev/null
+++ b/screenshots/cta-withdraw-ios-latest.png
@@ -0,0 +1 @@
+cta-withdraw-ios-0.png \ No newline at end of file
diff --git a/screenshots/cta-withdraw-review-android-0.png b/screenshots/cta-withdraw-review-android-0.png
new file mode 100644
index 00000000..3da47302
--- /dev/null
+++ b/screenshots/cta-withdraw-review-android-0.png
Binary files differ
diff --git a/screenshots/cta-withdraw-review-android-latest.png b/screenshots/cta-withdraw-review-android-latest.png
new file mode 120000
index 00000000..42dda6cf
--- /dev/null
+++ b/screenshots/cta-withdraw-review-android-latest.png
@@ -0,0 +1 @@
+cta-withdraw-review-android-0.png \ No newline at end of file
diff --git a/screenshots/cta-withdraw-review-chrome-0.png b/screenshots/cta-withdraw-review-chrome-0.png
new file mode 100644
index 00000000..97bdf5a4
--- /dev/null
+++ b/screenshots/cta-withdraw-review-chrome-0.png
Binary files differ
diff --git a/screenshots/cta-withdraw-review-chrome-latest.png b/screenshots/cta-withdraw-review-chrome-latest.png
new file mode 120000
index 00000000..18ba527b
--- /dev/null
+++ b/screenshots/cta-withdraw-review-chrome-latest.png
@@ -0,0 +1 @@
+cta-withdraw-review-chrome-0.png \ No newline at end of file
diff --git a/screenshots/enter_instance_details.png b/screenshots/enter_instance_details.png
new file mode 100644
index 00000000..f2177091
--- /dev/null
+++ b/screenshots/enter_instance_details.png
Binary files differ
diff --git a/screenshots/instance_iban_config.png b/screenshots/instance_iban_config.png
new file mode 100644
index 00000000..03fa8f36
--- /dev/null
+++ b/screenshots/instance_iban_config.png
Binary files differ
diff --git a/screenshots/merchant_first_login.png b/screenshots/merchant_first_login.png
new file mode 100644
index 00000000..0baa0801
--- /dev/null
+++ b/screenshots/merchant_first_login.png
Binary files differ
diff --git a/screenshots/no_default_account_yet.png b/screenshots/no_default_account_yet.png
new file mode 100644
index 00000000..c97c231d
--- /dev/null
+++ b/screenshots/no_default_account_yet.png
Binary files differ
diff --git a/screenshots/payment_links.png b/screenshots/payment_links.png
new file mode 100644
index 00000000..0c58b286
--- /dev/null
+++ b/screenshots/payment_links.png
Binary files differ
diff --git a/taler-auditor-manual.rst b/taler-auditor-manual.rst
index 58dc9463..94e86a8d 100644
--- a/taler-auditor-manual.rst
+++ b/taler-auditor-manual.rst
@@ -17,8 +17,13 @@
@author Christian Grothoff
-GNU Taler Auditor Operator Manual
-#################################
+Auditor Operator Manual
+#######################
+
+.. contents:: Table of Contents
+ :depth: 1
+ :local:
+
Introduction
============
@@ -29,14 +34,7 @@ to become readable.
About GNU Taler
---------------
-GNU Taler is an open protocol for an electronic payment system with a
-free software reference implementation. GNU Taler offers secure, fast
-and easy payment processing using well understood cryptographic
-techniques. GNU Taler allows customers to remain anonymous, while
-ensuring that merchants can be held accountable by governments. Hence,
-GNU Taler is compatible with anti-money-laundering (AML) and
-know-your-customer (KYC) regulation, as well as data protection
-regulation (such as GDPR).
+.. include:: frags/about-taler.rst
About this manual
@@ -65,7 +63,7 @@ all, the goal is to detect nerfarious activity of the exchange operator,
which cannot be effectively done on a machine controlled by the exchange
operator.
-For this, every auditor needs to operate a Postgres database. The data
+For this, every auditor needs to operate a PostgreSQL database. The data
collected will include sensitive information about Taler users, including
withdrawals made by consumers and income received by merchants. As a result,
the auditor is expected to provide high confidentiality for the database. In
@@ -118,7 +116,7 @@ third parties to verify one's own work.
The Taler software stack for an auditor consists of the following
components:
-- DBMS: Postgres
+- DBMS: PostgreSQL
The auditor requires a DBMS to store a local copy of the transaction history for
the Taler exchange, as well as for its own internal bookkeeping and checkpointing.
@@ -128,7 +126,7 @@ components:
concern that must be addressed manually. The software only verifies the content
of a well-formed exchange database (well-formed with respect to SQL).
For now, the GNU Taler reference implementation
- only supports Postgres, but the code could be easily extended to
+ only supports PostgreSQL, but the code could be easily extended to
support another DBMS.
- The auditor Web service
@@ -183,6 +181,8 @@ Installing from source
Please install the following packages before proceeding with the
exchange compilation.
+- Python3 module ``jinja2``
+
.. include:: frags/list-of-dependencies.rst
- GNU Taler exchange (from `download directory <http://ftpmirror.gnu.org/taler/>`__,
@@ -199,6 +199,8 @@ the exchange (which includes the code for the auditor).
.. include:: frags/installing-taler-exchange.rst
+.. include:: frags/install-before-check.rst
+
Installing the GNU Taler binary packages on Debian
--------------------------------------------------
@@ -264,7 +266,7 @@ Additionally, there are two canonical system users of relevance (which your
distribution would typically create for you):
* www-data --- runs the HTTPS frontend (usually nginx or Apache)
- * postgres --- runs the Postgres database
+ * postgres --- runs the PostgreSQL database
Databases and users
@@ -312,9 +314,6 @@ This section discusses configuration options related to the auditor.
.. include:: frags/configuration-format.rst
-.. include:: frags/using-taler-config.rst
-
-
.. _SetupBaseUrl:
Initial configuration
@@ -323,10 +322,11 @@ Initial configuration
You need to tell the Taler auditor configuration where the
REST API of the auditor will be available to the public:
-.. code-block:: console
+.. code-block:: ini
# Both for the 'offline' *and* the 'auditor' user:
- $ taler-config -s auditor -o BASE_URL -V https://auditor.example.com/
+ [auditor]
+ BASE_URL = https://auditor.example.com/
The ``helper`` user that is used to download information from the exchange
needs to know details about the exchange. Similarly, the ``offline`` user
@@ -335,11 +335,12 @@ need to obtain the ``MASTER_PUBLIC_KEY`` from the exchange operator (they need
to run ``taler-exchange-offline setup``) and the REST endpoint of the exchange
and configure these:
-.. code-block:: console
+.. code-block:: ini
# As the 'helper' and 'offline' users:
- $ taler-config -s exchange -o BASE_URL -V https://exchange.example.com/
- $ taler-config -s exchange -o MASTER_PUBLIC_KEY -V $SOMELONGBASE32VALUEHERE
+ [exchange]
+ BASE_URL = https://exchange.example.com/
+ MASTER_PUBLIC_KEY = $SOMELONGBASE32VALUEHERE
.. _AuditorKeys:
@@ -375,10 +376,11 @@ of the ``auditor`` user in the ``[auditor]]`` configuration section:
You can set this configuration value using:
-.. code-block:: console
+.. code-block:: ini
# As the 'auditor' and 'helper' users:
- $ taler-config -s auditor -o PUBLIC_KEY -V $SOMELONGBASE32VALUEHERE
+ [auditor]
+ PUBLIC_KEY = $SOMELONGBASE32VALUEHERE
.. _AuditorServing:
@@ -460,6 +462,12 @@ used when configuring the exchange' database:
CONFIG = postgres:///exchangedemo
+Legal conditions for using the service
+--------------------------------------
+
+.. include:: frags/legal.rst
+
+
.. _AuditorDeployment:
Deployment
@@ -579,9 +587,9 @@ The next key step for the auditor is to configure replication of the
*exchange*'s database in-house. This should be performed in two steps
as illustrated in the following figure:
-.. image:: replication.png
+.. image:: images/replication.png
-First, the exchange should use standard Postgres replication features to
+First, the exchange should use standard PostgreSQL replication features to
enable the auditor to obtain a full copy of the exchange's database.
Second, the auditor should make a "trusted" local copy, ensuring that it
never replicates malicious changes using ``taler-auditor-sync``. Both
@@ -591,7 +599,7 @@ We note that as a result of these steps, the auditor will have three
databases: its own production primary database (as configured in
``auditordb-postgres``), its on production copy of the exchange's database
(``exchangedb-postgress``), and a third, untrusted "ingres" copy of the
-exchange database. The untrusted database should run as a separate Postgres
+exchange database. The untrusted database should run as a separate PostgreSQL
instance and is only accessed via ``taler-auditor-sync`` and the replication
mechanism driven by the exchange operator.
@@ -603,7 +611,7 @@ Ingres operation should be done using the ``auditor-ingres`` user --- or
depending on the setup parts of the operation may be done by the ``postgres``
user directly.
-The full copy can be obtained in various ways with Postgres. It is
+The full copy can be obtained in various ways with PostgreSQL. It is
possible to use log shipping with streaming replication as described
in https://www.postgresql.org/docs/13/warm-standby.html, or to use
logical replication, as described in
@@ -612,7 +620,7 @@ that asynchronous replication should suffice.
The resulting auditor database should be treated as read-only on the auditor
side. The ``taler-exchange-dbinit`` tool can be used to setup the schema, or
-the schema can be replicated using Postgres's standard mechanisms. The same
+the schema can be replicated using PostgreSQL's standard mechanisms. The same
applies for schema upgrades: if logical replication is used (which does not
replicate schema changes), ``taler-exchange-dbinit`` can be used to migrate
the schema(s) in both the ingres and production copies of the exchange's
@@ -629,14 +637,14 @@ to perform database replication. This is done using:
$ echo "CREATE PUBLICATION $NAME FOR ALL TABLES;" | psql taler-exchange
The exchange must share the password of the publication with the auditor. A
-good ``$NAME`` relates to the auditor's buisness unit name. A secure tunnel
+good ``$NAME`` relates to the auditor's business unit name. A secure tunnel
must be setup between the exchange and the auditor, for example using SSH or
Wireguard.
It is also necessary to edit ``main.cf`` of the exchange and on the auditor
side to enable logical replication. If an exchange has multiple auditors, it
should setup multiple ``egress`` accounts. The exchange must ensure that
-the following lines are in the ``main.cf`` Postgres configuaration (the port
+the following lines are in the ``main.cf`` PostgreSQL configuration (the port
may differ) to enable replication over the network:
.. code-block::
@@ -646,7 +654,7 @@ may differ) to enable replication over the network:
wal_level= logical
Equally, the auditor must configure logical replication in the ``main.cf``
-Postgres configuaration:
+PostgreSQL configuration:
.. code-block::
@@ -655,11 +663,17 @@ Postgres configuaration:
Next, the ``postgres`` user of the auditor's system must first initialize the
local tables:
+.. code-block:: ini
+
+ # Configure database:
+ [exchange]
+ DB = "postgres"
+ [exchangedb-postgres]
+ CONFIG = "postgres:///taler-ingress"
+
.. code-block:: console
# As the 'ingress' user of the exchange:
- $ taler-config -s exchange -o DB -V "postgres"
- $ taler-config -s exchangedb-postgres -o CONFIG -V "postgres:///taler-ingress"
$ taler-exchange-dbinit
To complete the replication, the ``postgres`` user of the auditor's
@@ -673,7 +687,7 @@ system must subscribe:
$ echo "CREATE PUBLICATION $NAME FOR ALL TABLES;" | psql taler-exchange
-For details, we refer to the Postgres manual.
+For details, we refer to the PostgreSQL manual.
.. note::
@@ -682,9 +696,9 @@ For details, we refer to the Postgres manual.
``DROP`` operations on the tables. Hence, the auditor cannot rely upon the
exchange's primary copy to respect schema constraints, especially as we
have to presume that the exchange could act maliciously. Furthermore, it
- is unclear to what degree Postgres database replication mechanisms are
+ is unclear to what degree PostgreSQL database replication mechanisms are
robust against a malicious master database. Thus, the auditor should
- isolate its primary copy of the exchange database, including the Postgres
+ isolate its primary copy of the exchange database, including the PostgreSQL
process, from its actual operational data.
@@ -704,7 +718,7 @@ While ``taler-auditor-sync`` could in theory be run directly against the
exchange's production system, this is likely a bad idea due to the high
latency from the network between auditor and exchange operator. Thus, we
recommend first making an "untrusted" ingress copy of the exchange's
-production database using standard Postgres tooling, and then using
+production database using standard PostgreSQL tooling, and then using
``taler-auditor-sync`` to create a second "safe" copy. The "safe" copy used
by the production system should also run under a different UID.
@@ -719,11 +733,17 @@ needs to be changed.
To run ``taler-auditor-sync``, you must first configure two configuration
files that identify the source and destination databases:
-.. code-block:: console
+.. code-block:: ini
- # As the 'sync' user:
- $ taler-config -c src.conf -s exchangedb -o CONFIG -V "postgres:///auditor-ingres/"
- $ taler-config -c dst.conf -s exchangedb -o CONFIG -V "postgres:///auditor/"
+ # src.conf
+ [exchangedb]
+ CONFIG = "postgres:///auditor-ingres/"
+
+.. code-block:: ini
+
+ # dst.conf
+ [exchangedb]
+ CONFIG = "postgres:///auditor/"
Now you should be able to launch the synchronization process. You can run
the process via systemd in the background. For a first one-off test, you should
@@ -965,7 +985,7 @@ The auditor's database
The database scheme used by the exchange looks as follows:
-.. image:: auditor-db.png
+.. image:: images/auditor-db.png
Invariants checked by the auditor
diff --git a/taler-backoffice-manual.rst b/taler-backoffice-manual.rst
deleted file mode 100644
index 3042845d..00000000
--- a/taler-backoffice-manual.rst
+++ /dev/null
@@ -1,135 +0,0 @@
-.. _Top:
-
-Back-office Web service manual
-###############################
-
-.. _Introduction:
-
-Introduction
-============
-
-The back-office Web service allows a merchant to check on the status of
-their Taler transactions. Merchants can check if and when they were paid
-by a wire transfer for coins deposited at the exchange. Also, given a
-wire transfer they have received, they can ask which Taler transactions
-correspond to the wire transfer.
-
-This manual guides merchant system administrators through the
-installation and configuration of this Web service.
-
-.. _Installation:
-
-Installation
-============
-
-The back-office Web service code is available at
-``git://taler.net/backoffice``. The application can be installed in a
-GNU-ish fashion.
-
-.. code-block:: console
-
- # Get the code:
- $ git clone git://taler.net/backoffice
-
- # Bootstrap and configure
- $ cd backoffice
- $ ./bootstrap
- # This step will check if the system is ready to
- # allow the installation.
- $ ./configure --prefix=<PREFIX>
- $ make install
-
-Note that to make the application work ``<PREFIX>/bin`` must be included
-in the ``$PATH``, and ``<PREFIX>/lib/python3.7/site-packages/`` in
-``$PYTHONPATH``.
-
-.. _Configuration:
-
-Configuration
-=============
-
-The following information must be provided in the configuration: on
-which address the backend should serve the Web site, which currency is
-used, and which merchant backend this Web service will work with.
-
-The merchant backend is an important agent, as it is responsible for
-returning information about transactions and wire transfers. The
-backoffice Web service is merely a frontend for it. A separate manual
-(available at https://docs.taler.net/merchant/backend/html/manual.html)
-describes the installation and configuration of the merchant backend.
-
-Assuming the reader is familiar with configuration in Taler (if not,
-read:
-https://docs.taler.net/exchange/html/taler-exchange.html#Configuration-format),
-a working configuration example is the following one:
-
-.. code-block:: ini
-
- [taler]
- # will be EUR, USD, or whatever currency the merchant
- # works with.
- currency = KUDOS
-
- # each back-office Web service is associated with a "frontend
- # name": this name instructs the application which configuration
- # section is going to be read. Thus <name> is the "frontend name"
- # and must be specified on the command line via the "--frontend"
- # option. See the 'Run' chapter for more details on launching the
- # application.
- [backoffice-<name>]
-
- # This option sets the way the backoffice communicates
- # when it is instructed to operate via UWSGI. Therefore,
- # <how> can be: TCP or UNIX. If TCP is given, then the
- # additional UWSGI_PORT option becomes necessary.
- uwsgi_serve = <how>
-
- # those options will be read if the Web site is served via
- # WSGI.
- uwsgi_unixpath_mode = 660
- uwsgi_unixpath = /path/to/backoffice-<name>.uwsgi
- uwsgi_unixmode = 666
-
- # If UWSGI_SERVE were set as 'TCP', then the following option
- # would have been necessary. It instructs the backoffice service
- # about which TCP port should be listened on, to communicate over
- # UWSGI.
- # uwsgi_port = 8080
-
- # this option will be read if the Web site is served via
- # HTTP.
- http_port = 5959
-
- # specifies which merchant backend is going to be used.
- backend = http://backend.test.taler.net/
-
- # Informally speaking, each instance points to both a private
- # key that can sign proposals and a bank account that can receive
- # wire transfers by some exchange.
-
- # Here, <instance_i> is just a string (with no spaces) that will
- # make the referenced instance be traceable by the back-office Web
- # application.
-
- instances = <instance_1> <instance_2> ..
-
-.. _Launching-the-backoffice:
-
-Launching the backoffice
-========================
-
-The following example shows how to run the Web service.
-
-.. code-block:: console
-
- # Such invocation will work only if the configuration contains
- # a section called "[backoffice-myshop]" which looks like the
- # example above.
-
- # As of serving, the Web site will be available via HTTP, at the
- # port specified in the configuration option "http_port", at localhost.
-
- $ taler-merchant-backoffice --frontend myshop serve-http
-
-Other options, such as those to serve the site via WSGI, are explained
-in the man page and can be listed using the ``--help`` argument.
diff --git a/taler-bank-manual.rst b/taler-bank-manual.rst
deleted file mode 100644
index 6e282ba7..00000000
--- a/taler-bank-manual.rst
+++ /dev/null
@@ -1,71 +0,0 @@
-GNU Taler bank manual
-#####################
-
-Introduction
-============
-
-About GNU Taler
----------------
-
-GNU Taler is an open protocol for an electronic payment system with a
-free software reference implementation. GNU Taler offers secure, fast
-and easy payment processing using well understood cryptographic
-techniques. GNU Taler allows customers to remain anonymous, while
-ensuring that merchants can be held accountable by governments. Hence,
-GNU Taler is compatible with anti-money-laundering (AML) and
-know-your-customer (KYC) regulation, as well as data protection
-regulation (such as GDPR).
-
-About this manual
------------------
-
-This manual documents how the demonstrator bank interoperates with the
-other GNU Taler components. The demonstrator bank implements a simple
-closed banking system for the purpose of illustrating how GNU Taler
-works in the Taler demo. It could also be used as a starting point for a
-local/regional currency. Finally, “real” banks might use it as a
-reference implementation for a tight integration with the GNU Taler
-wallet.
-
-Headless Testing API Reference
-==============================
-
-The demonstrator bank offers the following APIs to allow automated testing. These APIs should
-be switched off during a production deployment.
-
-
-.. _bank-register:
-.. http:post:: /register
-
- This API provides programmatic user registration at the bank.
-
- **Request** The body of this request must have the format of a
- `BankRegistrationRequest`.
-
- **Response**
-
- :http:statuscode:`200 OK`:
- The new user has been correctly registered.
- :http:statuscode:`409 Conflict`:
- The username requested by the client is not available anymore.
- :http:statuscode:`400 Bad request`:
- Unacceptable characters were given for the username. See
- https://docs.djangoproject.com/en/2.2/ref/contrib/auth/#django.contrib.auth.models.User.username
- for the accepted character set.
-
-**Details**
-
-.. ts:def:: BankRegistrationRequest
-
- interface BankRegistrationRequest {
-
- // Username to use for registration; max length is 150 chars.
- username: string;
-
- // Password to associate with the username. Any characters and
- // any length are valid; next releases will enforce a minimum length
- // and a safer characters choice.
- password: string;
- }
-
-
diff --git a/taler-challenger-manual.rst b/taler-challenger-manual.rst
new file mode 100644
index 00000000..f9d6a793
--- /dev/null
+++ b/taler-challenger-manual.rst
@@ -0,0 +1,686 @@
+..
+ This file is part of GNU TALER.
+
+ Copyright (C) 2023, 2024 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Christian Grothoff
+ @author Florian Dold
+
+Challenger Operator Manual
+##########################
+
+.. contents:: Table of Contents
+ :depth: 2
+ :local:
+
+
+Introduction
+============
+
+About Challenger
+----------------
+
+Challenger is an OAuth 2.0-compatible address validation service.
+By redirecting a user-agent to a Challenger service a client can
+have Challenger validate that the user is able to receive messages
+at a particular address and obtain that address via the ``/info``
+endpoint.
+
+
+About this manual
+-----------------
+
+This manual targets system administrators who want to install,
+operate or integrate a challenger service. To report issues
+or learn about known limitations, please check our
+`bug tracker <https://bugs.taler.net>`__.
+
+
+Architecture overview
+---------------------
+
+The following picture gives an overview of the Challenger
+architecture and the main interactions:
+
+.. image:: images/challenger.png
+
+Here, the *resource owner* is a user that is in control
+of some *address* at a messaging service. This could be
+an e-mail account, a mobile phone number (for SMS), or
+a physical mail address (using the post office as the
+messaging service).
+
+The *resource owner* makes some request that requires
+some *client* to be in need of address validation. The
+*client* is registered with the Challenger OAuth 2.0
+service and first authorizes an address validation to
+be initiated. The client then redirects the resource
+owner to the Challenger service. In step (2), the resource
+owner submits the address that they claim to own.
+
+The Challenger service then creates a TAN code and
+submits it to the given address via a configurable
+*helper script* that is specific to the type of address
+being validated. When the resource owner submits the
+correct TAN code in step (6), they are given a token
+that they can provide to the client. Using this token
+the client can then finally obtain the now validated
+address in step (8).
+
+Address data, TAN codes and meta-data such as the number
+of failed attempts to submit a TAN code are recorded
+in a Postgres database by the Challenger service.
+
+.. _ChallengerInstallation:
+
+Installation
+============
+
+In this guide's shell-session fragments, the command prompt shows two pieces
+of information:
+
+* Who is performing the command
+ (``$user`` vs ``root``, and ending character ``$`` vs ``#``).
+
+
+Installing from source
+----------------------
+
+The following instructions will show how to install libgnunetutil and
+the core GNU Taler libraries from source.
+
+The package sources can be find in our
+`download directory <http://ftpmirror.gnu.org/taler/>`__.
+
+GNU Taler components version numbers follow the ``MAJOR.MINOR.MICRO`` format.
+The general rule for compatibility is that ``MAJOR`` and ``MINOR`` must match.
+Exceptions to this general rule are documented in the release notes.
+For example, Challenger 1.3.0 should be compatible with Taler exchange 1.4.x
+as the MAJOR version matches. A MAJOR version of 0 indicates experimental
+development, and you are expected to always run all of the *latest* releases
+together (no compatibility guarantees).
+
+First, the following packages need to be installed before we can compile the
+backend:
+
+.. include:: frags/list-of-dependencies.rst
+
+.. include:: frags/installing-gnunet.rst
+
+.. include:: frags/install-before-check.rst
+
+There is no need to actually run a GNUnet peer or a Taler exchange to use
+Challenger -- all Challenger needs from GNUnet and Taler are a number of
+headers and libraries!
+
+.. include:: frags/installing-taler-exchange.rst
+
+
+.. include:: frags/installing-challenger.rst
+
+.. include:: frags/install-before-check.rst
+
+
+
+Installing the Challenger binary packages on Debian
+---------------------------------------------------
+
+.. include:: frags/installing-debian.rst
+
+To install the Challenger, you can now simply run:
+
+.. code-block:: shell-session
+
+ # apt install challenger
+
+Note that the package does not perform any configuration work except for
+setting up the various users and the systemd service scripts. You still must
+configure at least the database, HTTP reverse proxy (typically with TLS
+certificates) and the terms of service.
+
+Installing the GNU Taler binary packages on Trisquel
+----------------------------------------------------
+
+.. include:: frags/installing-trisquel.rst
+
+Installing the GNU Taler binary packages on Ubuntu
+--------------------------------------------------
+
+.. include:: frags/installing-ubuntu.rst
+
+To install the Taler exchange, you can now simply run:
+
+.. code-block:: shell-session
+
+ # apt install challenger
+
+Note that the package does not perform any configuration work except for
+setting up the various users and the systemd service scripts. You still must
+configure at least the database, HTTP reverse proxy (typically with TLS
+certificates), and the terms of service.
+
+
+Services, users, groups and file system hierarchy
+-------------------------------------------------
+
+The *challenger* package will use several system users
+to compartmentalize different parts of the system:
+
+* ``challenger-httpd``: runs the HTTP daemon with the core business logic.
+* ``postgres``: runs the PostgreSQL database (from *postgresql* package).
+* ``www-data``: runs the frontend HTTPS service with the TLS keys (from *nginx* package).
+
+The package will deploy a systemd service files in
+``/usr/lib/systemd/system/`` for Challenger:
+
+* ``challenger-httpd.service``: the Challenger logic with the public REST API.
+
+
+Configuration Fundamentals
+==========================
+
+This chapter provides fundamental details about the exchange configuration.
+
+The configuration for all Taler components uses a single configuration file
+as entry point: ``/etc/challenger/challenger.conf``.
+
+System defaults are automatically loaded from files in
+``/usr/share/challenger/config.d``. These default files should never be modified.
+
+The default configuration ``challenger.conf`` configuration file also includes all
+configuration files in ``/etc/challenger/conf.d``.
+
+To view the entire configuration annotated with the source of each configuration option, you
+can use the ``challenger-config`` helper:
+
+
+.. code-block:: shell-session
+
+ [root@exchange-online]# challenger-config --diagnostics
+ < ... annotated, full configuration ... >
+
+.. warning::
+
+ While ``challenger-config`` also supports rewriting configuration files, we strongly
+ recommend to edit configuration files manually, as ``challenger-config`` does not
+ preserve comments and, by default, rewrites ``/etc/challenger/challenger.conf``.
+
+.. include:: frags/configuration-format.rst
+
+
+Fundamental Setup: Address validation
+-------------------------------------
+
+Each challenger service is designed to validate one type of address. Possible
+address types include:
+
+* phone numbers (via SMS)
+* e-mail addresses (via SMTP)
+* mail addresses (via postal service)
+
+In principle, additional types of addresses can easily be added by extending
+the respective HTML and programs to send challenges to the new address type.
+
+To make different types of address validations possible, the Challenger
+configuration contains two configuration options.
+
+(1) The ``ADDRESS_TYPE`` configuration option informs Challenger about the
+ type of address it is expected to validate. It is returned as part of
+ the OAuth 2.0 ``/info`` endpoint to the client, and is typically also
+ used when deciding how to render the HTML form for address entry that is
+ shown to the user.
+
+(2) The ``AUTH_COMMAND`` configuration option specifies which command
+ Challenger should run to send a challenge to an address. The actual
+ address is given to this subcommand as the first argument (``$1``),
+ while the text with the challenge is passed to standard input.
+ The subcommand should terminate with a status code of 0 on success.
+
+.. code-block:: ini
+ :caption: /etc/challenger/challenger.conf
+
+ [challenger]
+ ADDRESS_TYPE = email
+ AUTH_COMMAND = challenger-send-email.sh
+ # ... rest of file ...
+
+Challenger comes with ``AUTH_COMMAND`` shell scripts for sending e-mail, SMS
+and postal mail. Note that for SMS and postal mail the Challenger scripts uses
+third party services to actually send the SMS or print and mail the postal
+mail. These third parties naturally charge money for their services, and thus
+the Challenger administrator will need to add the respective credentials to
+the SMS and postal mail scripts before they can function. In any case, these
+scripts should be primarily seen as *examples* on how to write authentication
+commands.
+
+.. note::
+
+ We strongly welcome contributions for additional scripts with alternative
+ providers or for new types of addresses.
+
+
+Legal conditions for using the service
+--------------------------------------
+
+.. include:: frags/legal.rst
+
+Database Configuration
+----------------------
+
+The access credentials for the Challenger database are configured in
+``/etc/challenger/challenger.conf``. Currently, only PostgreSQL is
+supported as a database backend.
+
+.. note::
+
+ The **challenger-dbconfig** tool can be used to automate the database
+ setup. When using the Debian/Ubuntu packages, the user should already have
+ been created, so you can just run the tool without any arguments and should
+ have a working database configuration. Subsequently, you should still run
+ **taler-challenger-dbinit** as the ``challenger-httpd`` user to
+ initialize the database schema.
+
+
+To create a database for Challenger on the local system, run:
+
+.. code-block:: shell-session
+
+ [root@exchange-online]# su - postgres
+ [postgres@exchange-online]# createuser challenger-httpd
+ [postgres@exchange-online]# createdb -O challenger-httpd challenger
+ [postgres@exchange-online]# exit
+
+This will create a ``challenger`` database owned by the ``taler-httpd`` user.
+We will use that user later to perform database maintenance operations.
+
+Assuming the above database setup, the database credentials to configure
+in the configuration file would simply be:
+
+.. code-block:: ini
+ :caption: /etc/challenger/challenger.conf
+
+ [challenger]
+ DB = postgres
+
+ [challenger-postgres]
+ CONFIG = postgres:///challenger
+
+If the database is run on a different host, please follow the instructions
+from the PostgreSQL manual for configuring remote access.
+
+After configuring the database credentials, the Challenger database needs
+to be initialized with the following command:
+
+.. code-block:: shell-session
+
+ [root@exchange-online]# sudo -u challenger-httpd challenger-dbinit
+
+.. note::
+
+ To run this command, the user must have ``CREATE TABLE``, ``CREATE
+ INDEX``, ``ALTER TABLE`` and (in the future possibly even) ``DROP TABLE``
+ permissions. Those permissions are only required for this step (which may
+ have to be repeated when upgrading a deployment). Afterwards, during
+ normal operation, permissions to ``CREATE`` or ``ALTER`` tables are not
+ required by Challenger and thus should not be granted. For more
+ information, see :doc:`manpages/challenger-dbinit.1`.
+
+
+Deployment
+==========
+
+This chapter describes how to deploy Challenger once the basic installation
+and configuration are completed.
+
+.. _ChallengerServing:
+
+Serving
+-------
+
+The Challenger can serve HTTP over both TCP and UNIX domain socket.
+
+The following options are to be configured in the section ``[challenger]``:
+
+- ``SERVE``: Must be set to ``tcp`` to serve HTTP over TCP, or ``unix`` to serve
+ HTTP over a UNIX domain socket.
+
+- ``PORT``: Set to the TCP port to listen on if ``SERVE`` is ``tcp``.
+
+- ``UNIXPATH``: Set to the UNIX domain socket path to listen on if ``SERVE`` is
+ ``unix``.
+
+- ``UNIXPATH_MODE``: Number giving the mode with the access permission mask
+ for the ``UNIXPATH`` (i.e. 660 = ``rw-rw---``). Make sure to set it in such
+ a way that your reverse proxy has permissions to access the UNIX domain
+ socket. The default (660) assumes that the reverse proxy is a member of
+ the group under which the exchange HTTP server is running.
+
+.. _ChallengerReverseProxy:
+
+Reverse Proxy Setup
+-------------------
+
+By default, the ``challenger-httpd`` service listens for HTTP connections
+on a UNIX domain socket. To make the service publicly available, a reverse
+proxy such as nginx should be used. You must configure the reverse proxy
+to use TLS as this is required by OAuth 2.0.
+
+The ``challenger`` package ships with a sample configuration that can be
+enabled in nginx:
+
+.. code-block:: shell-session
+
+ [root@exchange-online]# vim /etc/nginx/sites-available/challenger
+ < ... customize configuration ... >
+ [root@exchange-online]# ln -s /etc/nginx/sites-available/challenger \
+ /etc/nginx/sites-enabled/challenger
+ [root@exchange-online]# systemctl reload nginx
+
+
+Launching Challenger
+--------------------
+
+A running exchange requires starting the following processes:
+
+- ``challenger-httpd`` (needs database access)
+
+The processes should be started via a hypervisor like
+``systemd`` or ``gnunet-arm`` that automatically re-starts them should they
+have terminated unexpectedly. Furthermore, the hypervisor
+*should* periodically re-start the service (say once per hour)
+to limit Postgres database memory utilization.
+
+.. note::
+
+ The ``challenger-httpd`` does not ship with HTTPS enabled by default.
+ It must thus be run behind an HTTPS reverse proxy that performs
+ TLS termination on the same system. Thus, it would typically be configured
+ to listen on a UNIX domain socket.
+
+Given proper packaging, all of the above are realized via a simple systemd
+target. This enables Challenger to be properly started using a simple command:
+
+.. code-block:: shell-session
+
+ # systemctl start challenger-httpd.service
+
+
+Authorizing clients
+-------------------
+
+Before clients can use Challenger, they must be explicitly configured. Each
+client is identified via its OAuth 2.0 REDIRECT URI. Thus, a client must have
+exactly one REDIRECT URI
+
+.. note::
+
+ The OAuth 2.0 specification allows for a client to register
+ zero or multiple REDIRECT URIs. However, zero is insecure
+ as it creates an open redirector, and multiple REDIRECT URIs
+ can trivially be implemented with Challenger by adding more
+ clients.
+
+You can add or remove clients at any time; the Challenger service does not
+need to be running, but if it is you can still add or remove clients without
+restarting the service. To add (or remove) a client, you must use the
+``challenger-admin`` command:
+
+.. code-block:: shell-session
+
+ # sudo -u challenger-httpd challenger-admin --add=$SECRET $REDIRECT_URI
+
+Here, ``$SECRET`` is the client secret of OAuth 2.0 which will be used in
+various parts of the protocol to authenticate the client. The
+``$REDIRECT_URI`` is the URI where the user-agent will be redirected to upon
+completion of the process. The ``challenger-admin`` command will
+then output the *client ID*, which will be a unique positive number.
+The first time you run the command, you will thus likely see:
+``Client added. Client ID is: 1``. This client ID, the ``$SECRET``
+and the ``$REDIRECT_URI`` will form the foundation for the OAuth 2.0
+configuration.
+
+
+OAuth 2.0 integration
+---------------------
+
+When integrating Challenger into an OAuth 2.0 process, you need to provide the
+three options from the previous section, but also the authorization, token and
+info endpoints. For Challenger, these are ``/authorize``, ``/token`` and
+``/info``. However, the ``/authorize`` endpoint is special, as it is actually
+``/authorize/$NONCE`` where ``$NONCE`` is a nonce that must be first requested
+by the client using the ``/setup/$CLIENT_ID`` endpoint!
+
+.. note::
+
+ This extra step prevents user-agents from (ab)using the Challenger service
+ to send challenges to addresses even when there is no authorized client
+ that desires address validation. This is an important feature as address
+ validation could be expensive.
+
+Thus, to generate the authorization URL, a client must first POST to
+``/setup/$CLIENT_ID`` using their client secret in an ``Authorization: Bearer $SECRET``
+HTTP header to obtain a fresh ``$NONCE``.
+
+In the GNU Taler exchange configuration, this is indicated by appending
+``#setup`` to the ``KYC_OAUTH2_AUTHORIZE_URL`` endpoint. Be careful to quote
+the URL, as ``#`` is otherwise interpreted as the beginning of a comment by
+the configuration file syntax:
+
+.. code-block:: ini
+ :caption: /etc/taler/conf.d/exchange-oauth2.conf
+
+ [kyc-provider-example-oauth2]
+ LOGIC = oauth2
+ # (generic options omitted)
+ KYC_OAUTH2_AUTHORIZE_URL = "https://challenger.example.com/authorize#setup"
+ KYC_OAUTH2_TOKEN_URL = "https://challenger.example.com/token"
+ KYC_OAUTH2_INFO_URL = "https://challenger.example.com/info"
+ KYC_OAUTH2_CLIENT_ID = 1
+ KYC_OAUTH2_CLIENT_SECRET = "$SECRET"
+
+
+
+Database management
+-------------------
+
+.. note::
+
+ We advise to make good backups before experimenting with
+ the database.
+
+To update the Challenger database after upgrading to a newer
+version of Challenger, you should simply re-run ``challenger-dbinit``.
+Without further options, this command is expected to preserve
+all data and only migrate the existing database to the latest
+schema:
+
+.. code-block:: console
+
+ $ challenger-dbinit
+
+To delete stale data from the Challenger database, you can use
+garbage collection:
+
+.. code-block:: console
+
+ $ challenger-dbinit --garbagecollect
+
+
+The Challenger database can be re-initialized using:
+
+.. code-block:: console
+
+ $ challenger-dbinit --reset
+
+However, running this command will result in all data in the database
+being lost.
+
+
+.. _ChallengerCustomization:
+
+Template Customization
+======================
+
+The Challenger service comes with various HTML templates that are shown to
+guide users through the process. Challenger uses `C implementation of mustache
+<https://gitlab.com/jobol/mustach>`__ as the templating engine. This section
+describes the various templates. In general, the templates must be installed
+to the ``share/challenger/templates/`` directory. The file names must be of
+the form ``$NAME.$LANG.must`` where ``$NAME`` is the name of the template and
+``$LANG`` is the 2-letter language code of the template. English templates
+must exist and will be used as a fallback. If the browser (user-agent) has
+provided language preferences in the HTTP header and the respective language
+exists, the correct language will be automatically served.
+
+The following subsections give details about each of the templates. The
+subsection title is the ``$NAME`` of the respective template.
+
+.. _challenger_enter-address_type-form:
+
+enter-$ADDRESS_TYPE-form
+------------------------
+
+These templates are used to ask the user to enter the address that challenger
+is expected to validate. Here, ``$ADDRESS_TYPE`` will be replaced by the
+``ADDRESS_TYPE`` configuration option in the ``[challenger]`` section of the
+configuration file. Typical values include ``address`` (for physical mailing
+addresses), ``phone`` (for mobile phone numbers) and ``email`` (for email
+addresses). For testing, ``file`` (where the TAN code is written into a local
+file) is also supported.
+
+The template is instantiated using the following information:
+
+* restrictions: Object; map of keys (names of the fields of the
+ address to be entered by the user) to objects with a "regex"
+ (string) containing an extended Posix regular expression for
+ allowed address field values, and a "hint"/"hint_i18n" giving
+ a human-readable explanation to display if the value entered
+ by the user does not match the regex. Keys that are not mapped
+ to such an object have no restriction on the value provided by
+ the user. See "ADDRESS_RESTRICTIONS" in the challenger
+ configuration.
+* fix_address: boolean; indicates if the given address cannot be changed
+ anymore, the form should be read-only if set to true.
+* nonce: String; unique value identifying the challenge, should be shown
+ to the user so that they can recognize it when they receive the TAN code
+* last_address: Object; form values from the previous submission if available,
+ details depend on the ``ADDRESS_TYPE``, should be used to pre-populate the form
+* changes_left: Integer; number of times the address can still be changed,
+ may or may not be shown to the user
+
+.. _challenger_enter-tan-form:
+
+enter-tan-form
+--------------
+
+This page should generate the HTML form for the user to enter the TAN code
+that they received at the respective address.
+
+The template is instantiated using the following information:
+
+* nonce: String; unique value identifying the challenge, should be shown
+ to the user so that they can match it to the TAN code they received
+* attempts_left: Integer; how many more attempts are allowed, might be
+ shown to the user, highlighting might be appropriate for low values
+ such as 1 or 2 (the form will never be used if the value is zero)
+* address: Object; the address that is being validated, might be shown
+ or not
+* transmitted: boolean; true if we just retransmitted the challenge,
+ false if we sent a challenge recently and thus refused to transmit it
+ again this time; might make a useful hint to the user
+* next_tx_time: String; timestamp explaining when we would re-transmit
+ the challenge the next time (at the earliest) if requested by the user
+
+
+.. _challenger_invalid-pin:
+
+invalid-pin
+-----------
+
+The user has provided an invalid TAN code (HTTP 403 Forbidden).
+
+The template is instantiated using the following information:
+
+* ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+* hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+* addresses_left: Integer; how many times is the user still allowed to
+ change the address; if 0, the user should not be shown a link to jump
+ to the address entry form
+* pin_transmissions_left: Integer; how many times might the PIN still
+ be retransmitted
+* auth_attempts_left: Integer; how many times might the user still try
+ entering the PIN code
+* exhausted: Bool; if true, the PIN was not even evaluated as the user
+ previously exhausted the number of attempts
+* no_challenge: Bool; if true, the PIN was not even evaluated as no
+ challenge was ever issued (the user must have skipped the step of
+ providing their address first!)
+
+If both *pin_transmissions_left* and *auth_attempts_left* are zero, the link
+to re-enter the PIN should be hidden and the user should only be allowed to
+specify a different address. The form will never be generated if all three
+values are zero. (Thus there is always at least one valid choice when the form
+is shown.)
+
+
+.. _challenger_validation-unknown:
+
+validation-unknown
+------------------
+
+The user has tried to access a validation process that is not known to the
+backend (HTTP 404 Not Found).
+
+The template is instantiated using the following information:
+
+* ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+* hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+* detail: String; optional, extended human-readable text provided to elaborate
+ on the error, should be shown to provide additional context
+
+.. _challenger_invalid-request:
+
+invalid-request
+---------------
+
+The request of the client is invalid (HTTP 400 Bad Request).
+
+The template is instantiated using the following information:
+
+* ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+* hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+* detail: String; optional, extended human-readable text provided to elaborate
+ on the error, should be shown to provide additional context
+
+.. _challenger_internal-error:
+
+internal-error
+--------------
+
+The service experienced an internal error (HTTP 500 Internal Server Error).
+
+The template is instantiated using the following information:
+
+* ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+* hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+* detail: String; optional, extended human-readable text provided to elaborate
+ on the error, should be shown to provide additional context
diff --git a/taler-developer-manual.rst b/taler-developer-manual.rst
index fdb2a81c..3035e55d 100644
--- a/taler-developer-manual.rst
+++ b/taler-developer-manual.rst
@@ -1,7 +1,7 @@
..
This file is part of GNU TALER.
- Copyright (C) 2014-2021 Taler Systems SA
+ Copyright (C) 2014-2023 Taler Systems SA
TALER 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
@@ -20,11 +20,6 @@ Developer's Manual
##################
.. toctree::
- :hidden:
-
- checklist-release
- checklist-demo-upgrade
-
.. note::
@@ -32,11 +27,171 @@ Developer's Manual
and related components. It is not intended for a general audience.
.. contents:: Table of Contents
+ :depth: 2
+ :local:
+
+
+Project Overview
+================
+
+GNU Taler consists of a large (and growing) number of components
+in various Git repositories. The following list gives a first
+overview:
+
+ * exchange: core payment processing logic with a REST API, plus various
+ helper processes for interaction with banks and cryptographic
+ computations. Also includes the logic for the auditor and an
+ in-memory "bank" API implementation for testing.
+
+ * libeufin: implementation of the "bank" API using the EBICS protocol
+ used by banks in the EU. Allows an exchange to interact with
+ European banks.
+
+ * deploymerization: implementation of the "bank" API on top of
+ blockchains, specifically Bitcoin and Ethereum. Allows an exchange
+ to interact with crypto-currencies.
+
+ * merchant: payment processing backend to be run by merchants,
+ offering a REST API.
+
+ * wallet-core: platform-independent implementation of a wallet to be run by
+ normal users. Includes also the WebExtension for various browsers.
+ Furthermore, includes various single-page apps used by other
+ components (especially as libeufin and merchant). Also includes
+ command-line wallet and tools for testing.
+
+ * taler-android: Android Apps including the Android wallet, the
+ Android point-of-sale App and the Android casher app.
+
+ * taler-ios: iOS wallet App.
+
+ * sync: backup service, provides a simple REST API to allow users to
+ make encrypted backups of their wallet state.
+
+ * anastasis: key escrow service, provides a simple REST API to allow
+ users to distribute encryption keys across multiple providers and
+ define authorization policies for key recovery.
+ * taler-mdb: integration of Taler with the multi-drop-bus (MDB) API
+ used by vending machines. Allows Taler payments to be integrated
+ with vending machines.
+
+ * gnu-taler-payment-for-woocommerce: payment plugin for the
+ woocommerce (wordpress) E-commerce solution.
+
+ * twister: man-in-the-middle proxy for tests that require fuzzing a
+ REST/JSON protocol. Used for some of our testing.
+
+ * challenger: implementation of an OAuth 2.0 provider that can be used
+ to verify that a user can receive SMS or E-mail at particular addresses.
+ Used as part of KYC processes of the exchange.
+
+ * taler-mailbox: messaging service used to store and forward payment
+ messages to Taler wallets.
+
+ * taldir: directory service used to lookup Taler wallet addresses for
+ sending invoices or payments to other wallets.
+
+ * taler-merchant-demos: various demonstration services operated at
+ 'demo.taler.net', including a simple shop and a donation page.
+
+There are other important repositories without code, including:
+
+ * gana: Hosted on git.gnunet.org, this repository defines various
+ constants used in the GNU Taler project.
+
+ * docs: documentation, including this very document.
+
+ * marketing: various presentations, papers and other resources for
+ outreach.
+
+ * large-media: very large data objects, such as videos.
+
+ * www: the taler.net website.
Fundamentals
============
+Versioning
+----------
+
+A central rule is to never break anything for any dependency. To accomplish
+this, we use versioning, of the APIs, database schema and the protocol. The
+database versioning approach is described in the :ref:`Database schema
+versioning <DatabaseVersioning>` section. Here, we will focus on API and
+protocol versioning.
+
+The key issue we need to solve with protocols and APIs (and that does not
+apply to database versioning) is being able to introduce and remove features
+without requiring a flag day where all components must update at the same
+time. For this, we use GNU libtool style versioning with MAJOR:REVISION:AGE
+and *not* semantic versioning (SEMVER). With GNU libtool style versioning,
+first the REVISION should be increased on every change to the respective code.
+Then, each time a feature is introduced or deprecated, the MAJOR and AGE
+numbers are increased. Whenever an API is actually removed the AGE number is
+reduced to match the distance since the removed API was deprecated. Thus, if
+some client implements version X of the protocol (including not using any APIs
+that have been deprecated), it is compatible for any implementation where
+MAJOR is larger or equal to X, and MAJOR minus AGE is smaller or equal to X.
+REVISION is not used for expected compatibility issues and merely serves to
+uniquely identify each version (in combination with MAJOR).
+
+To evolve any implementation, it is thus critical to first of all never
+just break an existing API or endpoint. The only acceptable modifications
+are to return additional information (being aware of binary compatibility!)
+or to accept additional optional arguments (again, in a way that does not
+break existing users). Thus, the most common way to introduce changes will
+be the addition of new endpoints. Breaking existing endpoints is only ever
+at best acceptable while in the process of introducing it and if you are
+absolutely sure that there are zero users in other components.
+
+When removing endpoints (or fields being returned), you must first deprecate
+the existing API (incrementing MAJOR and AGE) and then wait for all clients,
+including all clients in operation (e.g. Android and iOS Apps, e-commerce
+integrations, etc.) to upgrade to a protocol implementation above the
+deprecated MAJOR revision. Only then you should remove the endpoint and reduce
+AGE.
+
+To document these changes, please try to use ``@since`` annotations in the API
+specifications to explain the MAJOR revision when a feature became available,
+but most importantly use ``@deprecated X`` annotations to indicate that an API
+was deprecated and will be removed once MAJOR minus AGE is above X. When using
+an API, use the ``/config`` endpoints to check for compatibility and show a
+warning if the version(s) you support and the version(s) offered by the server
+are incompatible.
+
+
+Testing Tools
+-------------
+
+For full ``make check`` support, install these programs:
+
+- `jq <https://github.com/stedolan/jq>`__
+- `curl <http://curl.haxx.se>`__
+- `faketime <https://github.com/wolfcw/libfaketime>`__
+
+The ``make check`` should be able to function without them, but
+their presence permits some tests to run that would otherwise be skipped.
+
+Manual Testing Database Reset
+-----------------------------
+
+Sometimes ``make check`` will fail with some kind of database (SQL)
+error, perhaps with a message like ``OBJECT does not exist`` in the
+``test-suite.log`` file, where ``OBJECT`` is the name of a table or function.
+In that case, it may be necessary to reset the ``talercheck`` database
+with the commands:
+
+.. code-block:: console
+
+ $ dropdb talercheck
+ $ createdb talercheck
+
+This is because, at the moment, there is no support for
+doing these steps automatically in the ``make check`` flow.
+
+(If ``make check`` still fails after the reset, file a bug report as usual.)
+
Bug Tracking
------------
@@ -143,11 +298,74 @@ development.
Communication
-------------
-We use the #taler channel on the Freenode IRC network and the taler@gnu.org
-public mailinglist for discussions. Not all developers are active on IRC, but
-all developers should probably subscribe to the low-volume Taler mailinglist.
-There are separate low-volume mailinglists for gnunet-developers (@gnu.org)
-and for libmicrohttpd (@gnu.org).
+For public discussions we use the taler@gnu.org mailinglist. All developers
+should subscribe to the low-volume Taler mailinglist. There are separate
+low-volume mailinglists for gnunet-developers (@gnu.org) and for libmicrohttpd
+(@gnu.org). For internal discussions we use https://mattermost.taler.net/
+(invitation only, but also achieved).
+
+
+What to put in bootstrap
+------------------------
+
+Each repository has a ``bootstrap`` script, which contains commands for the
+developer to run after a repository checkout (i.e., after ``git clone`` or
+``git pull``).
+Typically, this updates and initializes submodules, prepares the tool chain,
+and runs ``autoreconf``.
+The last step generates the ``configure`` script, whether for immediate use or
+for inclusion in the distribution tarball.
+
+One common submodule is ``contrib/gana``, which pulls from the
+`GNUnet GANA repository <https://git.gnunet.org/gana.git/>`__.
+For example, in the
+`Taler exchange repository <https://git.taler.net/exchange.git>`__,
+the bootstrap script eventually runs the ``git submodule update --init`` command
+early on, and later runs script ``./contrib/gana-generate.sh``, which
+generates files such as ``src/include/taler_signatures.h``.
+
+Thus, to update that file, you need to:
+
+- (in GANA repo) Find a suitable (unused) name and number for the Signature
+ Purposes database.
+
+- Add it to GANA, in ``gnunet-signatures/registry.rec``.
+ (You can check for uniqueness with the ``recfix`` utility.)
+
+- Commit the change, and push it to the GANA Git repo.
+
+- (in Taler Repo) Run the ``contrib/gana-latest.sh`` script.
+
+- Bootstrap, configure, do ``make install``, ``make check``, etc.
+ (Basically, make sure the change does not break anything.)
+
+- Commit the submodule change, and push it to the Taler exchange Git repo.
+
+A similar procedure is required for other databases in GANA.
+See file ``README`` in the various directories for specific instructions.
+
+
+Debian and Ubuntu Repositories
+==============================
+
+We package our software for Debian and Ubuntu.
+
+Nightly Repositories
+--------------------
+
+To try the latest, unstable and untested versions of packages,
+you can add the nightly package sources.
+
+.. code-block:: shell-session
+
+ # For Ubuntu (focal-fossa)
+ $ echo "deb https://deb.taler.net/apt-nightly focal-taler-nightly main" > /etc/apt/sources.list.d/taler.list
+
+ # For Debian (bullseye)
+ $ echo "deb https://deb.taler.net/apt-nightly bullseye-taler-nightly main" > /etc/apt/sources.list.d/taler.list
+
+ # Both: Install signing key for nightly packages
+ $ wget -O - https://taler.net/taler-systems-nightly.gpg.key | apt-key add -
Language-Specific Guidelines
@@ -159,22 +377,19 @@ Language-Specific Guidelines
Taler Deployment on gv.taler.net
================================
-This section describes the GNU Taler deployment on ``gv.taler.net``.
-``gv`` is our server at BFH. It hosts the Git repositories, Web sites,
-CI and other services. Developers can receive an SSH account and
-e-mail alias for the system. As with Git, ask your primary team
-contact for shell access if you think you need it.
+This section describes the GNU Taler deployment on ``gv.taler.net``. ``gv``
+is our server at BFH. It hosts the Git repositories, Web sites, CI and other
+services. Developers can receive an SSH account and e-mail alias for the
+system, you should contact Javier, Christian or Florian. As with Git, ask
+your primary team contact for shell access if you think you need it.
-Our old server, ``tripwire``, is currently offline and will likely
-go back online to host ``production`` systems for operating real
-Taler payments at BFH in the future.
DNS
---
-DNS records for taler.net are controlled by the GNU Taler
-maintainers, specifically Christian and Florian. If you
-need a sub-domain to be added, please contact one of them.
+DNS records for taler.net are controlled by the GNU Taler maintainers,
+specifically Christian and Florian, and our system administrator, Javier. If
+you need a sub-domain to be added, please contact one of them.
User Acccounts
@@ -189,29 +404,63 @@ serve Taler on the Internet:
- ``taler-internal``: serves ``*.int.taler.net``, and does *NOT* get
automatically built.
-The following two users are *never* automatically built, and they both
-serve ``*.demo.taler.net``. At any given time, only one is active and
-serves the HTTP requests from the outside; the other one can so be
-compiled without any downtime. If the compilation succeeds, the inactive
-user can be switched to become active (see next section), and vice versa.
-
-- ``demo-blue``
-- ``demo-green``
+- ``demo``: serves ``*.demo.taler.net``. Never automatically built.
Demo Upgrade Procedure
======================
+#. Login as the ``demo`` user on ``gv.taler.net``.
+#. Pull the latest ``deployment.git`` code.
+#. Navigate to the ``deployment.git/docker/demo`` directory.
+#. Refer to the README, or the smaller cheat sheet below.
+
+The deployment is based on rootless Docker, managed by the
+SystemD unit in userspace: ``docker.service``. The running daemon
+is reached by every Docker command at the address held into the
+``DOCKER_HOST`` environment variable. Normally, it points to
+``unix:///run/user/$(id -u)/docker.sock``. Such variable is automatically
+exported by ``~/.bashrc``.
+
+.. note::
+
+ Should the rootless Docker be installed, run the following command
+ or consult the `official documentation <https://docs.docker.com/engine/security/rootless/>`_.
+
+ .. code-block:: console
+
+ $ curl -fsSL https://get.docker.com/rootless | sh
+
Upgrading the ``demo`` environment should be done with care, and ideally be
coordinated on the mailing list before. It is our goal for ``demo`` to always
run a "working version" that is compatible with various published wallets.
+Please use the :doc:`demo upgrade checklist <checklists/checklist-demo-upgrade>` to make
+sure everything is working.
+Nginx is already configured to reach the services as exported by
+Docker Compose.
-Before deploying on ``demo``, the same version of all components **must**
-be deployed *and* tested on ``int``.
-Please use the :doc:`demo upgrade checklist <checklist-demo-upgrade>` to make
-sure everything is working.
+Cheat sheet
+-----------
+
+All commands run from deployment.git/docker/demo.
+
+.. code-block:: console
+
+ # Start services.
+ $ docker-compose start --remove-orphans -d
+ # Stop services.
+ $ docker-compose stop
+
+ # Build base image (without tags-file builds master)
+ $ ./build_base.sh images/base/Dockerfile [tags-file]
+
+ # Build all the services based on the latest base image
+ $ docker-compose build
+
+ # View live logs of the daemonized services.
+ $ docker-compose logs
Tagging components
------------------
@@ -227,99 +476,7 @@ All Taler components must be tagged with git before they are deployed on the
DD = day
SS = serial
-
-Environment Layout
-------------------
-
-Environments have the following layout:
-
-.. code-block:: none
-
- $HOME/
- deployment (deployment.git checkout)
- envcfg.py (configuration of the Taler environment)
- activate (bash file, sourced to set environment variables)
- logs/ (log files)
- local/ (locally installed software)
- sources/ (sources repos of locally build components)
- sockets/ (unix domain sockets of running components)
- taler-data (on-disk state, public and private keys)
- .config/taler.conf (main Taler configuration file)
-
-On ``demo-blue`` and ``demo-green``, ``taler-data`` is a symlink pointing to ``$HOME/demo/shared-data``
-instead of a directory.
-
-
-Using envcfg.py
----------------
-
-The ``$HOME/envcfg.py`` file contains (1) the name of the environment and (2) the version
-of all components we build (in the form of a git rev).
-
-The ``envcfg.py`` for demo looks like this:
-
-.. code-block:: python
-
- env = "demo"
- tag = "demo-2019-10-05-01:
- tag_gnunet = tag
- tag_libmicrohttpd = tag
- tag_exchange = tag
- tag_merchant = tag
- tag_bank = tag
- tag_twister = tag
- tag_landing = tag
- tag_donations = tag
- tag_blog = tag
- tag_survey = tag
- tag_backoffice = tag
- tag_sync = tag
-
-Currently only the variables ``env`` and ``tag_${component}`` are used.
-
-When deploying to ``demo``, the ``envcfg.py`` should be committed to ``deployment.git/envcfg/envcfg-demo-YYYY-MM-DD-SS.py``.
-
-
-Bootstrapping an Environment
-----------------------------
-
-.. code-block:: console
-
- $ git clone https://git.taler.net/deployment.git ~/deployment
- $ cp ~/deployment/envcfg/$ENVCFGFILE ~/envcfg.py
- $ ./deployment/bin/taler-deployment bootstrap
- $ source ~/activate
- $ taler-deployment build
- $ taler-deployment-prepare
- $ taler-deployment-start
- $ taler-deployment-arm -I # check everything works
- # The following command sets up the 'blog' and 'donations' instances.
- $ taler-config-instances
-
-
-Upgrading an Existing Environment
----------------------------------
-
-.. code-block:: console
-
- $ rm -rf ~/sources ~/local
- $ git -C ~/deployment pull
- $ cp ~/deployment/envcfg/$ENVCFGFILE ~/envcfg.py
- $ taler-deployment bootstrap
- $ taler-deployment build
- $ taler-deployment-prepare
- $ taler-deployment-restart
- $ taler-deployment-arm -I # check everything works
-
-Switching Demo Colors
----------------------
-
-As the ``demo`` user, to switch to color ``${COLOR}``,
-run the following script from ``deployment/bin``:
-
-.. code-block:: console
-
- $ taler-deployment switch-demo
+.. include:: checklists/checklist-demo-upgrade.rst
Environments and Builders on taler.net
@@ -353,12 +510,46 @@ Best Practices:
Then make sure there is a WORKER defined in master.cfg like: ``worker.Worker("<username>", "<password>")``
+Test builder
+------------
+
+This builder (``test-builder``) compiles and starts every Taler component.
+The associated worker is run by the ``taler-test`` Gv user, via the SystemD
+unit ``buildbot-worker-taler``. The following commands start/stop/restart
+the worker:
+
+.. code-block::
+
+ systemctl --user start buildbot-worker-taler
+ systemctl --user stop buildbot-worker-taler
+ systemctl --user restart buildbot-worker-taler
+
+.. note::
+ the mentioned unit file can be found at ``deployment.git/systemd-services/``
+
+Wallet builder
+--------------
+
+This builder (``wallet-builder``) compiles every Taler component
+and runs the wallet integration tests. The associated worker is
+run by the ``walletbuilder`` Gv user, via the SystemD unit ``buildbot-worker-wallet``.
+The following commands start/stop/restart the worker:
+
+.. code-block::
+
+ systemctl --user start buildbot-worker-wallet
+ systemctl --user stop buildbot-worker-wallet
+ systemctl --user restart buildbot-worker-wallet
+
+.. note::
+ the mentioned unit file can be found at ``deployment.git/systemd-services/``
+
Documentation Builder
---------------------
All the Taler documentation is built by the user ``docbuilder`` that
runs a Buildbot worker. The following commands set the ``docbuilder`` up,
-starting with a empty home directory.
+starting with an empty home directory.
.. code-block:: console
@@ -380,7 +571,7 @@ Website Builder
Taler Websites, ``www.taler.net`` and ``stage.taler.net``, are built by the
user ``taler-websites`` by the means of a Buildbot worker. The following
-commands set the ``taler-websites`` up, starting with a empty home directory.
+commands set the ``taler-websites`` up, starting with an empty home directory.
.. code-block:: console
@@ -417,47 +608,6 @@ by Buildbot.
The results are then published at ``https://lcov.taler.net/``.
-Service Checker
----------------
-
-The user ``demo-checker`` runs periodic checks to see if all the
-``*.demo.taler.net`` services are up and running. It is driven by
-Buildbot, and can be bootstrapped as follows.
-
-.. code-block:: console
-
- # Log-in as the 'demo-checker' user
-
- $ cd $HOME
- $ git clone git://git.taler.net/deployment
- $ ./deployment/bootstrap-demochecker
-
- # If the previous step worked, the setup is
- # complete and the Buildbot worker can be started.
-
- $ buildbot-worker start worker/
-
-
-Tipping reserve top-up
-----------------------
-
-Both 'test' and 'demo' setups get their tip reserve topped up
-by a Buildbot worker. The following steps get the reserve topper
-prepared.
-
-.. code-block:: console
-
- # Log-in as <env>-topper, with <env> being either 'test' or 'demo'
-
- $ git clone git://git.taler.net/deployment
- $ ./deployment/prepare-reservetopper <env>
-
- # If the previous steps worked, then it should suffice to start
- # the worker, with:
-
- $ buildbot-worker start worker/
-
-
Producing auditor reports
-------------------------
@@ -470,7 +620,7 @@ prepared.
# Log-in as <env>-auditor, with <env> being either 'test' or 'demo'
$ git clone git://git.taler.net/deployment
- $ ./deployment/prepare-auditorreporter <env>
+ $ ./deployment/buildbot/bootstrap-scripts/prepare-auditorreporter <env>
# If the previous steps worked, then it should suffice to start
# the worker, with:
@@ -478,11 +628,13 @@ prepared.
$ buildbot-worker start worker/
+.. _DatabaseVersioning:
+
Database schema versioning
--------------------------
-The Postgres databases of the exchange and the auditor are versioned.
-See the 0000.sql file in the respective directory for documentation.
+The PostgreSQL databases of the exchange and the auditor are versioned.
+See the ``versioning.sql`` file in the respective directory for documentation.
Every set of changes to the database schema must be stored in a new
versioned SQL script. The scripts must have contiguous numbers. After
@@ -490,17 +642,22 @@ any release (or version being deployed to a production or staging
environment), existing scripts MUST be immutable.
Developers and operators MUST NOT make changes to database schema
-outside of this versioning.
+outside of this versioning. All tables of a GNU Taler component should live in their own schema.
+QA Plans
+========
+
+.. include:: checklists/qa-0.9.4.rst
+
Releases
========
-Release Process and Checklists
-------------------------------
+.. include:: checklists/checklist-release.rst
-Please use the :doc:`release checklist <checklist-release>`
+Release Process
+---------------
This document describes the process for releasing a new version of the
various Taler components to the official GNU mirrors.
@@ -509,10 +666,11 @@ The following components are published on the GNU mirrors
- taler-exchange (exchange.git)
- taler-merchant (merchant.git)
-- talerdonations (donations.git)
-- talerblog (blog.git)
-- taler-bank (bank.git)
-- taler-wallet-webex (wallet-webex.git)
+- sync (sync.git)
+- taler-mdb (taler-mdb.git)
+- libeufin (libeufin.git)
+- challenger (challenger.git)
+- wallet-core (wallet-core.git)
Tagging
-------
@@ -615,6 +773,7 @@ Directive file:
version: 1.2
directory: taler
filename: taler-exchange-0.1.0.tar.gz
+ symlink: taler-exchange-0.1.0.tar.gz taler-exchange-latest.tar.gz
Upload the files in **binary mode** to the ftp servers.
@@ -635,21 +794,25 @@ debian/changelog, and then run:
in the respective source directory (GNUnet, exchange, merchant) to create the
``.deb`` files. Note that they will be created in the parent directory. This
can be done on gv.taler.net, or on another (secure) machine.
+Actual release builds should be done via the Docker images
+that can be found in ``deployment.git`` under packaging.
+
+On ``gv``, we use the ``aptbuilder`` user to manage the reprepro repository.
Next, the ``*.deb`` files should be copied to gv.taler.net, say to
-``/root/incoming``. Then, run
+``/home/aptbuilder/incoming``. Then, run
.. code-block:: bash
- # cd /var/www/repos/apt/debian/
- # reprepro includedeb sid /root/incoming/*.deb
+ # cd /home/aptbuilder/apt
+ # reprepro includedeb bullseye ~/incoming/*.deb
-to import all Debian files from ``/root/incoming/`` into the ``sid``
+to import all Debian files from ``~/incoming/`` into the ``bullseye``
distribution. If Debian packages were build against other distributions,
reprepro may need to be first configured for those and the import command
updated accordingly.
-Finally, make sure to clean up ``/root/incoming/`` (by deleting the
+Finally, make sure to clean up ``~/incoming/`` (by deleting the
now imported ``*.deb`` files).
@@ -767,6 +930,56 @@ weblate.taler.net signs GPG commits with the GPG key CD33CE35801462FA5EB0B695F26
This means that contributions made through weblate will not be signed with the individual contributor's key when they are checked into the Git repository, but with the weblate key.
+
+iOS Apps
+========
+
+.. _Build-iOS-from-source:
+
+Building Taler Wallet for iOS from source
+-----------------------------------------
+
+The GNU Taler Wallet iOS app is in
+`the official Git repository <https://git.taler.net/taler-ios.git>`__.
+
+Compatibility
+^^^^^^^^^^^^^
+
+The minimum version of iOS supported is 15.0.
+This app runs on all iPhone models at least as new as the iPhone 6S.
+
+
+Building
+^^^^^^^^
+
+Before building the iOS wallet, you must first checkout the
+`quickjs-tart repo <https://git.taler.net/quickjs-tart.git>`__
+and the
+`wallet-core repo <https://git.taler.net/wallet-core.git>`__.
+
+Have all 3 local repos (wallet-core, quickjs-tart, and this one) adjacent at
+the same level (e.g. in a "GNU_Taler" folder)
+Taler.xcworkspace expects the QuickJS framework sub-project to be at
+``../quickjs-tart/QuickJS-rt.xcodeproj``.
+
+Build wallet-core first:
+
+.. code-block:: shell-session
+
+ $ cd wallet-core
+ $ make embedded
+ $ open packages/taler-wallet-embedded/dist
+
+then drag or move its product "taler-wallet-core-qjs.mjs"
+into your quickjs-tart folder right at the top level.
+
+Open Taler.xcworkspace, and set scheme / target to Taler_Wallet. Build&run...
+
+Don't open QuickJS-rt.xcodeproj or TalerWallet.xcodeproj and build anything
+there - all needed libraries and frameworks will be built automatically from
+Taler.xcworkspace.
+
+
Android Apps
============
@@ -964,7 +1177,7 @@ then published at https://lcov.taler.net/ .
Coding Conventions
==================
-GNU Taler is developed primarily in C, Kotlin, Python and TypeScript.
+GNU Taler is developed primarily in C, Kotlin, Python, Swift and TypeScript.
Components written in C
-----------------------
@@ -1097,6 +1310,19 @@ are useful:
* ``subprocess`` for "shelling out" to other programs. Prefer ``subprocess.run``
over the older APIs.
+
+Swift
+-----
+
+Please follow best practices for the language.
+
+
+TypeScript
+----------
+
+Please follow best practices for the language.
+
+
Testing library
===============
@@ -1104,7 +1330,7 @@ This chapter is a VERY ABSTRACT description of how testing is
implemented in Taler, and in NO WAY wants to substitute the reading of
the actual source code by the user.
-In Taler, a test case is a array of ``struct TALER_TESTING_Command``,
+In Taler, a test case is an array of ``struct TALER_TESTING_Command``,
informally referred to as ``CMD``, that is iteratively executed by the
testing interpreter. This latter is transparently initiated by the
testing library.
@@ -1127,7 +1353,7 @@ CMDs: for example, CMD1 may create some key material and CMD2 needs this
key material to encrypt data.
The offering of internal values from CMD1 to CMD2 is made by *traits*. A
-trait is a ``struct TALER_TESTING_Trait``, and each CMD contains a array
+trait is a ``struct TALER_TESTING_Trait``, and each CMD contains an array
of traits, that it offers via the public trait interface to other
commands. The definition and filling of such array happens transparently
to the test developer.
@@ -1184,9 +1410,15 @@ Refreshing
**Use instead**: "Obtaining change"
+Charge
+ Charge has two opposite meanings (charge to a credit card vs. charge a battery).
+ This can confuse users.
+
+ **Use instead**: "Obtain", "Credit", "Debit", "Withdraw", "Top up"
+
Coin
Coins are an internal construct, the user should never be aware that their balance
- is represented by coins if different denominations.
+ is represented by coins of different denominations.
**Use instead**: "(Digital) Cash" or "(Wallet) Balance"
@@ -1292,18 +1524,16 @@ use when talking to end users or even system administrators.
trusted third party that verifies that the :term:`exchange` is operating correctly
bank
- traditional financial service provider who offers wire :term:`transfers <transfer>` between accounts
+ traditional financial service provider who offers
+ :term:`wire transfers <wire transfer>` between accounts
buyer
individual in control of a Taler :term:`wallet`, usually using it to
- :term:`spend` the :term:`coins` on :term:`contracts` (see also :term:`customer`).
+ :term:`spend` the :term:`coins <coin>` on :term:`contracts <contract>` (see also :term:`customer`).
close
- closes
- closed
- closing
operation an :term:`exchange` performs on a :term:`reserve` that has not been
- :term:`drained` by :term:`withdraw` operations. When closing a reserve, the
+ :term:`emptied <empty>` by :term:`withdraw` operations. When closing a reserve, the
exchange wires the remaining funds back to the customer, minus a :term:`fee`
for closing
@@ -1311,10 +1541,8 @@ use when talking to end users or even system administrators.
individual that directs the buyer (perhaps the same individual) to make a purchase
coin
- coins
coins are individual token representing a certain amount of value, also known as the :term:`denomination` of the coin
- commitment
refresh commitment
data that the wallet commits to during the :term:`melt` stage of the
:term:`refresh` protocol where it
@@ -1323,9 +1551,8 @@ use when talking to end users or even system administrators.
probabilistically (see: :term:`kappa`) during the :term:`reveal` stage.
contract
- contracts
formal agreement between :term:`merchant` and :term:`customer` specifying the
- :term:`contract terms` and signed by the merchant and the :term:`coins` of the
+ :term:`contract terms` and signed by the merchant and the :term:`coins <coin>` of the
customer
contract terms
@@ -1341,32 +1568,32 @@ use when talking to end users or even system administrators.
particular :term:`denomination`
deposit
- deposits
- depositing
operation by which a merchant passes coins to an exchange, expecting the
exchange to credit his bank account in the future using an
:term:`aggregate` :term:`wire transfer`
drain
- drained
- a :term:`reserve` is being drained when a :term:`wallet` is using the
- reserve's private key to :term:`withdraw` coins from it. This reduces
- the balance of the reserve. Once the balance reaches zero, we say that
- the reserve has been (fully) drained. Reserves that are not drained
- (which is the normal process) are :term:`closed` by the exchange.
+ process by which an exchange operator takes the profits
+ (from :term:`fees <fee>`) out of the escrow account and moves them into
+ their regular business account
dirty
- dirty coin
- a coin is dirty if its public key may be known to an entity other than
+ a :term:`coin` is dirty if its public key may be known to an entity other than
the customer, thereby creating the danger of some entity being able to
link multiple transactions of coin's owner if the coin is not refreshed
+ empty
+ a :term:`reserve` is being emptied when a :term:`wallet` is using the
+ reserve's private key to :term:`withdraw` coins from it. This reduces
+ the balance of the reserve. Once the balance reaches zero, we say that
+ the reserve has been (fully) emptied. Reserves that are not emptied
+ (which is the normal process) are :term:`closed <close>` by the exchange.
+
exchange
Taler's payment service operator. Issues electronic coins during
withdrawal and redeems them when they are deposited by merchants
expired
- expiration
Various operations come with time limits. In particular, denomination keys
come with strict time limits for the various operations involving the
coin issued under the denomination. The most important limit is the
@@ -1388,18 +1615,17 @@ use when talking to end users or even system administrators.
fee
an :term:`exchange` charges various fees for its service. The different
fees are specified in the protocol. There are fees per coin for
- :term:`withdrawing`, :term:`depositing`, :term:`melting`, and
- :term:`refunding`. Furthermore, there are fees per wire transfer
- for :term:`closing` a :term:`reserve`: and for
- :term:`aggregate` :term:`wire transfers` to the :term:`merchant`.
+ :term:`withdrawing <withdraw>`, :term:`depositing <deposit>`, :term:`melting <melt>`, and
+ :term:`refunding <refund>`. Furthermore, there are fees per wire transfer
+ when a :term:`reserve` is :term:`closed <close>`
+ and for :term:`aggregate` :term:`wire transfers <wire transfer>`
+ to the :term:`merchant`.
fresh
- fresh coin
- a coin is fresh if its public key is only known to the customer
+ a :term:`coin` is fresh if its public key is only known to the customer
- json
JSON
- JavaScript Object Notation
+ JavaScript Object Notation (JSON) is a
serialization format derived from the JavaScript language which is
commonly used in the Taler protocol as the payload of HTTP requests
and responses.
@@ -1409,11 +1635,11 @@ use when talking to end users or even system administrators.
The probability of successfully evading the income transparency with the
refresh protocol is 1:kappa.
- LibEuFin
- FIXME: explain
+ libeufin
+ Kotlin component that implements a regional currency bank and an
+ adapter to communicate via EBICS with European core banking systems.
link
- linking
specific step in the :term:`refresh` protocol that an exchange must offer
to prevent abuse of the :term:`refresh` mechanism. The link step is
not needed in normal operation, it just must be offered.
@@ -1423,9 +1649,7 @@ use when talking to end users or even system administrators.
message signing keys
melt
- melted
- melting
- step of the :term:`refresh` protocol where a :term:`dirty coin`
+ step of the :term:`refresh` protocol where a :term:`dirty` :term:`coin`
is invalidated to be reborn :term:`fresh` in a subsequent
:term:`reveal` step.
@@ -1436,7 +1660,9 @@ use when talking to end users or even system administrators.
key used by the exchange to sign online messages, other than coins
order
- FIXME: to be written!
+ offer made by the merchant to a wallet; pre-cursor to
+ a contract where the wallet is not yet fixed. Turns
+ into a :term:`contract` when a wallet claims the order.
owner
a coin is owned by the entity that knows the private key of the coin
@@ -1449,19 +1675,19 @@ use when talking to end users or even system administrators.
recoup
Operation by which an exchange returns the value of coins affected
- by a :term:`revocation` to their :term:`owner`, either by allowing the owner to
+ by a :term:`revocation <revoke>` to their :term:`owner`, either by allowing the owner to
withdraw new coins or wiring funds back to the bank account of the :term:`owner`.
planchet
precursor data for a :term:`coin`. A planchet includes the coin's internal
secrets (coin private key, blinding factor), but lacks the RSA signature
- of the :term:`exchange`. When :term:`withdrawing`, a :term:`wallet`
+ of the :term:`exchange`. When :term:`withdrawing <withdraw>`, a :term:`wallet`
creates and persists a planchet before asking the exchange to sign it to
get the coin.
purchase
Refers to the overall process of negotiating a :term:`contract` and then
- making a payment with :term:`coins` to a :term:`merchant`.
+ making a payment with :term:`coins <coin>` to a :term:`merchant`.
privacy policy
Statement of an operator how they will protect the privacy of users.
@@ -1474,13 +1700,11 @@ use when talking to end users or even system administrators.
merchant backend.
refresh
- refreshing
- operation by which a :term:`dirty coin` is converted into one or more
- :term:`fresh` coins. Involves :term:`melting` the :term:`dirty coin` and
- then :term:`revealing` so-called :term:`transfer keys`.
+ operation by which a :term:`dirty` :term:`coin` is converted into one or more
+ :term:`fresh` coins. Involves :term:`melting <melt>` the :term:`dirty` coins and
+ then :term:`revealing <reveal>` so-called :term:`transfer keys <transfer key>`.
refund
- refunding
operation by which a merchant steps back from the right to funds that he
obtained from a :term:`deposit` operation, giving the right to the funds back
to the customer
@@ -1492,25 +1716,23 @@ use when talking to end users or even system administrators.
reserve
accounting mechanism used by the exchange to track customer funds
- from incoming :term:`wire transfers`. A reserve is created whenever
+ from incoming :term:`wire transfers <wire transfer>`. A reserve is created whenever
a customer wires money to the exchange using a well-formed public key
in the subject. The exchange then allows the customer's :term:`wallet`
to :term:`withdraw` up to the amount received in :term:`fresh`
- :term:`coins` from the reserve, thereby draining the reserve. If a
- reserve is not drained, the exchange eventually :term:`closes` it.
+ :term:`coins <coin>` from the reserve, thereby emptying the reserve. If a
+ reserve is not emptied, the exchange will eventually :term:`close` it.
Other definition: Funds set aside for future use; either the balance of a customer at the
exchange ready for withdrawal, or the funds kept in the exchange;s bank
account to cover obligations from coins in circulation.
reveal
- revealing
step in the :term:`refresh` protocol where some of the transfer private
keys are revealed to prove honest behavior on the part of the wallet.
In the reveal step, the exchange returns the signed :term:`fresh` coins.
revoke
- revocation
exceptional operation by which an exchange withdraws a denomination from
circulation, either because the signing key was compromised or because
the exchange is going out of operation; unspent coins of a revoked
@@ -1522,22 +1744,14 @@ use when talking to end users or even system administrators.
time.
spend
- spending
operation by which a customer gives a merchant the right to deposit
coins in return for merchandise
- transfer
- transfers
- wire transfer
- wire transfers
- method of sending funds between :term:`bank` accounts
-
transfer key
- transfer keys
special cryptographic key used in the :term:`refresh` protocol, some of which
are revealed during the :term:`reveal` step. Note that transfer keys have,
- despite the name, no relationship to :term:`wire transfers`. They merely
- help to transfer the value from a :term:`dirty coin` to a :term:`fresh coin`
+ despite the name, no relationship to :term:`wire transfers <wire transfer>`. They merely
+ help to transfer the value from a :term:`dirty` coin to a :term:`fresh` coin
terms
the general terms of service of an operator, possibly including
@@ -1570,25 +1784,27 @@ use when talking to end users or even system administrators.
Cross-browser API used to implement the GNU Taler wallet browser extension.
wire gateway
- FIXME: explain
+ API used by the exchange to talk with some real-time gross settlement system
+ (core banking system, blockchain) to notice inbound credits wire transfers
+ (during withdraw) and to trigger outbound debit wire transfers (primarily
+ for deposits).
+
+ wire transfer
+ a wire transfer is a method of sending funds between :term:`bank` accounts
wire transfer identifier
- wtid
Subject of a wire transfer from the exchange to a merchant;
set by the aggregator to a random nonce which uniquely
identifies the transfer.
withdraw
- withdrawing
- withdrawal
operation by which a :term:`wallet` can convert funds from a :term:`reserve` to
fresh coins
zombie
- zombie coin
- coin where the respective :term:`denomination key` is past its
- :term:`deposit` :term:`expiration` time, but which is still (again) valid
- for an operation because it was :term:`melted` while it was still
+ :term:`coin` where the respective :term:`denomination key` is past its
+ :term:`deposit` :term:`expiration <expired>` time, but which is still (again) valid
+ for an operation because it was :term:`melted <melt>` while it was still
valid, and then later again credited during a :term:`recoup` process
@@ -1600,84 +1816,12 @@ This section describes various internal programs to make life easier for the
developer.
-taler-config-generate
----------------------
-
-**taler-config-generate** - tool to simplify Taler configuration generation
-
-
-**taler-config-generate**
-[**-C** *CURRENCY* | **--currency=**\ ‌\ *CURRENCY*]
-[**-c** *FILENAME* | **--config=**\ ‌\ *FILENAME*]
-[**-e** | **--exchange**]
-[**-f** *AMOUNT* | *--wirefee=*\ ‌\ *AMOUNT*]
-[**-h** | **--help**]
-[**-J** *JSON* | **--wire-json-exchange=**\ ‌\ *JSON*]
-[**-j** *JSON* | **--wire-json-merchant=**\ ‌\ *JSON*]
-[**-L** *LOGLEVEL* | **--loglevel=**\ ‌\ *LOGLEVEL*]
-[**-m** | **--merchant**]
-[**-t** | **--trusted**]
-[**-v** | **--version**]
-[**-w** *WIREFORMAT* | **--wire** *WIREFORMAT*]
-[**--bank-uri**]
-[**--exchange-bank-account**]
-[**--merchant-bank-account**]
-
-
-**taler-config-generate** can be used to generate configuration files
-for the Taler exchange or Taler merchants.
-
-**-C** *CURRENCY* \| **--currency=**\ ‌\ *CURRENCY*
- Which currency should we use in the configuration.
-
-**-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME*
- Location where to write the generated configuration. Existing file
- will be updated, not overwritten.
-
-**-e** \| **--exchange**
- Generate configuration for a Taler exchange.
-
-**-f** *AMOUNT* \| *-wirefee=*\ ‌\ *AMOUNT*
- Setup wire transfer fees for the next 5 years for the exchange (for
- all wire methods).
-
-**-h** \| **--help**
- Shows this man page.
-
-**-J** *JSON* \| **--wire-json-exchange=**\ ‌\ *JSON*
- Wire configuration to use for the exchange.
-
-**-j** *JSON* \| **--wire-json-merchant=**\ ‌\ *JSON*
- Wire configuration to use for the merchant.
-
-**-L** *LOGLEVEL* \| **--loglevel=**\ ‌\ *LOGLEVEL*
- Use LOGLEVEL for logging. Valid values are DEBUG, INFO, WARNING and
- ERROR.
-
-**-m** \| **--merchant**
- Generate configuration for a Taler merchant.
-
-**-t** \| **--trusted**
- Setup current exchange as trusted with current merchant. Generally
- only useful when configuring for testcases.
-
-**-v** \| **--version**
- Print version information.
-
-**-w** *WIREFORMAT* \| **--wire** *WIREFORMAT*
- Specifies which wire format to use (i.e. “test” or “sepa”)
+taler-harness
+-------------
-**--bank-uri**
- Alternative to specify wire configuration to use for the exchange and
- merchant for the “test” wire method. Only useful if WIREFORMAT was
- set to “test”. Specifies the URI of the bank.
+**taler-harness deployment gen-coin-config** is a tool to simplify Taler configuration generation.
-**--exchange-bank-account**
- Alternative to specify wire configuration to use for the exchange for
- the “test” wire method. Only useful if WIREFORMAT was set to “test”.
- Specifies the bank account number of the exchange.
-**--merchant-bank-account**
- Alternative to specify wire configuration to use for the merchant for
- the “test” wire method. Only useful if WIREFORMAT was set to “test”.
- Specifies the bank account number of the merchant.
+**taler-harness deployment gen-coin-config**
+[**-min-amount**=**\ ‌\ *VALUE*]
+[**-max-amount**=**\ ‌\ *VALUE*]
diff --git a/taler-exchange-manual.rst b/taler-exchange-manual.rst
index ef0d501a..91865f24 100644
--- a/taler-exchange-manual.rst
+++ b/taler-exchange-manual.rst
@@ -1,7 +1,7 @@
..
This file is part of GNU TALER.
- Copyright (C) 2014-2020 Taler Systems SA
+ Copyright (C) 2014-2024 Taler Systems SA
TALER 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
@@ -15,59 +15,51 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
@author Christian Grothoff
+ @author Florian Dold
+
+Exchange Operator Manual
+########################
+
+.. contents:: Table of Contents
+ :depth: 1
+ :local:
-GNU Taler Exchange Operator Manual
-##################################
Introduction
============
-This manual is an early draft that still needs significant editing work
-to become readable.
-
About GNU Taler
---------------
-GNU Taler is an open protocol for an electronic payment system with a
-free software reference implementation. GNU Taler offers secure, fast
-and easy payment processing using well understood cryptographic
-techniques. GNU Taler allows customers to remain anonymous, while
-ensuring that merchants can be held accountable by governments. Hence,
-GNU Taler is compatible with anti-money-laundering (AML) and
-know-your-customer (KYC) regulation, as well as data protection
-regulation (such as GDPR).
-
-GNU Taler is not yet production-ready, after following this manual you
-will have a backend that can process payments in “KUDOS”, but not
-regular currencies. This is not so much because of limitations in the
-backend, but because we are not aware of a Taler exchange operator
-offering regular currencies today.
+.. include:: frags/about-taler.rst
+
About this manual
-----------------
-This tutorial targets system administrators who want to install and
+This manual targets system administrators who want to install and
operate a GNU Taler exchange.
+
Organizational prerequisites
----------------------------
-Operating a GNU Taler exchange means that you are operating a payment
-service provider, which means that you will most likely need a bank
-license and/or follow applicable financial regulation.
+Operating a GNU Taler exchange means that you are operating a payment service
+provider, which means that you will most likely need a bank license and/or
+follow applicable financial regulation. Exceptions may apply, especially if
+you are operating a regional currency or a payment system for an event with a
+closed user group.
-GNU Taler payment service providers generally need to ensure high
-availability and have *really* good backups (synchronous replication,
-asynchronous remote replication, off-site backup, 24/7 monitoring,
-etc.). This manual will not cover these aspects of operating a
-payment service provider.
+GNU Taler payment service providers generally need to ensure high availability
+and should have *really* good backups (synchronous replication, asynchronous
+remote replication, off-site backup, 24/7 monitoring, etc.). This manual will
+not cover these aspects of operating a payment service provider.
-We will assume that you can operate a (high-availability,
-high-assurance) Postgres database. Furthermore, we expect some moderate
+We will assume that you can operate a (sufficiently high-availability,
+high-assurance) PostgreSQL database. Furthermore, we expect some moderate
familiarity with the compilation and installation of free software
-packages. You need to understand the cryptographic concepts of private
-and public keys and must be able to protect private keys stored in files
-on disk.
+packages. You need to understand the cryptographic concepts of private and
+public keys and must be able to protect private keys stored in files on disk.
.. include:: frags/db-stores-sensitive-data.rst
@@ -75,58 +67,65 @@ on disk.
Architecture overview
---------------------
-Taler is a pure payment system, not a new crypto-currency. As such, it
-operates in a traditional banking context. In particular, this means
-that in order to receive funds via Taler, the merchant must have a
-regular bank account, and payments can be executed in ordinary
-currencies such as USD or EUR. Similarly, the Taler exchange must
-interact with a bank. The bank of the exchange holds the exchange’s
-funds in an escrow account.
-
-Note that, given the technical burden (XML-based communications,
-additional cryptography, and a vast variety of standards) due to
-interact with banks, the exchange uses a intermediary system to talk
-to its bank. Such intermediary system abstracts the native banking
-protocol by exposing the *Taler Wire Gateway API*; this way, the exchange
-can conduct its banking operations in a simplified and JSON-based style.
-
-When customers wire money to the escrow account, the bank notifies the
-exchange about the incoming wire transfers. The exchange then creates a
-*reserve* based on the subject of the wire transfer. The wallet which
-knows the secret key matching the wire transfer subject can then
-withdraw coins from the reserve, thereby draining it. The liability of
-the exchange against the reserve is thereby converted into a liability
-against digital coins issued by the exchange. When the customer later
-spends the coins at a merchant, and the merchant *deposits* the coins at
+GNU Taler is a pure payment system, not a crypto-currency. As such, it
+operates in a traditional banking context. In particular, this means that
+payments can be executed in ordinary currencies such as USD or EUR.
+Furthermore, a typical merchant in Taler has a regular bank account, and would
+use it to receive funds via Taler.
+
+Consequently, a typical Taler exchange must interact with a bank. The bank of
+the exchange holds funds in an account where the balance is basically
+equivalent to the value of all coins in circulation. (Small mismatches arise
+whenever customers are about to withdraw coins and have already send the funds
+into the bank account, or if merchants just deposited coins and are about to
+receive wire transfers for deposited coins, or due to fees charged by the
+exchange and the operator not yet having drained the fees from the account.)
+
+The exchange uses an intermediary system to talk to its bank. This shifts the
+technical burden (XML-based communications, additional cryptography, and a
+vast variety of standards) for this interaction into another bank-specific
+subsystem. Such intermediary system abstracts the native banking protocol by
+exposing the *Taler Wire Gateway API*; this way, the exchange can conduct its
+banking operations in a simplified and JSON-based style.
+
+When customers wire money to the exchange's bank account, the Taler Wire
+Gateway API must notify the exchange about the incoming wire transfers. The
+exchange then creates a *reserve* based on the subject of the wire
+transfer. The wallet which knows the secret key matching the wire transfer
+subject can then withdraw coins from the reserve, thereby draining it. The
+liability of the exchange against the reserve is thereby converted into a
+liability against digital coins issued by the exchange. When the customer
+later spends the coins at a merchant, and the merchant *deposits* the coins at
the exchange, the exchange first *aggregates* the amount from multiple
-deposits from the same merchant and then instructs its bank to make a
-wire transfer to the merchant, thereby fulfilling its obligation and
-eliminating the liability. The exchange charges *fees* for some or all
-of its operations to cover costs and possibly make a profit.
+deposits from the same merchant and then instructs its bank to make a wire
+transfer to the merchant, thereby fulfilling its obligation and eliminating
+the liability. The exchange charges *fees* for some or all of its operations
+to cover costs and possibly make a profit.
-*Auditors* are third parties, for example financial regulators, that
-verify that the exchange operates correctly. The same software is also
-used to calculate the exchange’s profits, risk and liabilities by the
-accountants of the exchange.
+*Auditors* are third parties, for example financial regulators, that verify
+that the exchange operates correctly. The same software is also used to
+calculate the exchange’s profits, risk and liabilities by the accountants of
+the exchange.
The Taler software stack for an exchange consists of the following
components:
-- HTTP frontend
+- **HTTP frontend**:
The HTTP frontend interacts with Taler wallets and merchant backends.
It is used to withdraw coins, deposit coins, refresh coins, issue
refunds, map wire transfers to Taler transactions, inquire about the
exchange’s bank account details, signing keys and fee structure. The
binary is the ``taler-exchange-httpd``.
-- Crypto-Helpers
- The ``taler-exchange-secmod-rsa`` and ``taler-exchange-secmod-eddsa``
- are two programs that are responsible for managing the exchange's
+- **Crypto-Helpers**:
+ The ``taler-exchange-secmod-rsa``, ``taler-exchange-secmod-cs`` and
+ ``taler-exchange-secmod-eddsa``
+ are three programs that are responsible for managing the exchange's
online signing keys. They must run on the same machine as the
``taler-exchange-httpd`` as the HTTP frontend communicates with the
crypto helpers using UNIX Domain Sockets.
-- Aggregator
+- **Aggregator**:
The aggregator combines multiple deposits made by the same merchant
and (eventually) triggers wire transfers for the aggregate amount.
The merchant can control how quickly wire transfers are made. The
@@ -134,14 +133,14 @@ components:
excessively frequent transfers. The binary is the
``taler-exchange-aggregator``.
-- Closer
+- **Closer**:
The ``taler-exchange-closer`` tool check that reserves are properly
closed. If a customer wires funds to an exchange and then fails
to withdraw them, the closer will (eventually) trigger a wire
transfer that sends the customer's funds back to the originating
wire account.
-- Transfer
+- **Transfer**:
The ``taler-exchange-transfer`` tool is responsible for actually
executing the aggregated wire transfers. It is the only process
that needs to have the credentials to execute outgoing wire
@@ -151,7 +150,7 @@ components:
by LibEuFin. LibEuFin is an adapter which maps the Taler Wire
REST API to traditional banking protocols like EBICS and FinTS.
-- Wirewatch
+- **Wirewatch**:
The ``taler-exchange-wirewatch`` tool is responsible for observing
incoming wire transfers to the exchange. It needs to have the
credentials to obtain a list of incoming wire transfers.
@@ -160,32 +159,36 @@ components:
making outgoing wire transfers is done via different bank accounts
and/or credentials.
-- Wire adapter
+- **Wire adapter**:
A wire adapter is a component that enables exchange to talk to a bank.
-
- (1) The libtalerfakebank implements a bank with a wire adapter API
- inside of a testcase.
- (2) For the demonstration Web site (or local currencies),
- the Python bank provides a bank that directly provides
- the wire adapter API.
- (3) For production, libeufin's Nexus component implements a wire
- adapter towards the traditional SEPA banking system with IBAN
- accounts.
-
- The client-side wire adapter API is implemented in libtalerbank and
- is used by the transfer to execute wire transfers and for the
- auditor to query bank transaction histories.
-
-
-- DBMS
+ Each wire adapter must implement the Taler Wire Gateway API. Three
+ wire adapters are currently provided:
+
+ (1) The **libtalerfakebank** implements a bank with a wire adapter API
+ inside of a testcase. ``taler-fakebank-run`` is a stand-alone
+ process using libtalerfakebank. Note that this adapter is only
+ useful for tests, as all transaction data is kept in memory.
+ (2) For production, **libeufin**'s ``libeufin-nexus`` component
+ implements a wire adapter towards the traditional SEPA banking
+ system with IBAN accounts using the EBICS protocol.
+ (3) To use GNU Taler with blockchains, the **Depolymerization**
+ component provides a wire gateway API that runs on top of
+ blockchains like Bitcoin and Ethereum.
+
+ The client-side wire adapter API is implemented in **libtalerbank** and
+ is used by ``taler-exchange-transfer`` to execute wire transfers and by
+ ``taler-exchange-wirewatch`` and the Taler auditor auditor to query bank
+ transaction histories.
+
+- **DBMS**:
The exchange requires a DBMS to stores the transaction history for
the Taler exchange and aggregator, and a (typically separate) DBMS
for the Taler auditor. For now, the GNU Taler reference implementation
- only supports Postgres, but the code could be easily extended to
+ only supports PostgreSQL, but the code could be easily extended to
support another DBMS.
- .. index:: Postgres
+ .. index:: PostgreSQL
-- Auditor
+- **Auditor**:
The auditor verifies that the transactions performed by the exchange
were done properly. It checks the various signatures, totals up the
amounts and alerts the operator to any inconsistencies. It also
@@ -193,13 +196,38 @@ components:
exchange operator. The main binary is the ``taler-auditor``.
Aside from the key setup procedures, the most critical setup for
deploying an auditor is providing the auditor with an up-to-date
- copy of the database.
+ copy of the exchange's database.
+
+
+.. _KeyTypes:
+
+Key Types
+---------
+
+The exchange works with four types of keys:
+
+- master key (kept offline, configured manually at merchants and wallets)
+
+- online message signing keys (signs normal messages from the exchange)
+
+- denomination keys (signs digital coins)
+
+- security module keys (signs online message signing keys and denomination keys)
+
+Additionally, the exchange is sometimes concerned with the auditor's public
+key (to verify messages signed by auditors approved by the exchange operator)
+and the merchant's public key (to verify refunds are authorized by the
+merchant).
+
+Most of the keys are managed fully automatically or configured as part of the
+denomination configuration. Some configuration settings must be manually
+set with regards to the exchange's master key.
Offline keys
------------
-The exchange (and ideally also auditors) uses a long-term offline master
+The exchange (and ideally also its auditor(s)) uses a long-term offline master
siging key that identifies the operator and is used to authenticate critical
information, such as the exchange's bank account and the actual keys the
exchange uses online.
@@ -212,11 +240,10 @@ computing power, a Raspberry-Pi is perfectly sufficient and the form-factor
might be good for safe-keeping! (You should keep a copy of the (encrypted)
private offline key on more than one physical medium though.)
-Exchange operators are strongly advised to secure your private master key and
-any copies on encrypted, always-offline computers. Again, we assume that you
-are familiar with good best practices in operational security, including
-securing key material.
-
+Exchange operators are strongly advised to secure their private master key and
+any copies on encrypted, always-offline computers. Again, this manual assumes
+that you are familiar with good best practices in operational security,
+including securing key material.
Online signing key security
@@ -224,8 +251,8 @@ Online signing key security
To provide an additional level of protection for the private *online* signing
keys used by the exchange, the actual cryptographic signing operations are
-performed by two helper processes, the ``taler-exchange-secmod-rsa`` and the
-``taler-exchange-secmod-eddsa``.
+performed by three helper processes, ``taler-exchange-secmod-rsa``,
+``taler-exchange-secmod-cs`` and ``taler-exchange-secmod-eddsa``.
The current implementation does not yet support the use of a hardware security
module (HSM). If you have such a device with adequate functionality and are
@@ -236,8 +263,10 @@ integration support.
Functionality
^^^^^^^^^^^^^
-The UNIX domain sockets have mode 0620 (u+rw, g+w). The exchange process
-MUST be in the same group as the crypto helper processes.
+The UNIX domain sockets of the *secmod* helpers have mode 0620 (u+rw, g+w).
+The exchange process MUST thus be in the same group as the crypto helper
+processes to enable access to the keys. No other users should be in that
+group!
The two helper processes will create the required private keys, and allow
anyone with access to the UNIX domain socket to sign arbitrary messages with
@@ -245,6 +274,7 @@ the keys or to inform them about a key being revoked. The helper processes
are also responsible for deleting the private keys if their validity period
expires or if they are informed about a key having been revoked.
+
Security goals
^^^^^^^^^^^^^^
@@ -261,44 +291,60 @@ Setup
^^^^^
The helper processes should be run under a user ID that is separate from that
-of the user running the main ``taler-exchange-httpd`` service. For security,
-it is important that helpers run under a different user ID than the main HTTP
-frontend, in fact ideally each helper should run under its own user ID. The
-``taler-exchange-httpd`` service's will securely communicate with the helpers
-using UNIX domain sockets. To enable access to the keys, the service's user
-must be in the group of the helper processes (and no other users should be in
-that group).
+of the user running the main ``taler-exchange-httpd`` service. To get any
+security benefit from this, it is important that helpers run under a different
+user ID than the main HTTP frontend. In fact, ideally, each helper should run
+under its own user ID. The ``taler-exchange-httpd`` service's will securely
+communicate with the helpers using UNIX domain sockets.
Configuration
^^^^^^^^^^^^^
-The helpers and the HTTP service need both access to the same configuration
-information. Having divergent configurations may result in run-time failures.
-It is recommended that the configuration file (``-c`` option) is simply shared
-between all of the different processes, even though they run as different
-system users. The configuration does not contain any sensitive information.
-
+The helpers and the exchange HTTP service need both access to the same
+configuration information. Having divergent configurations may result in
+run-time failures. It is recommended that the configuration file (``-c``
+option) is simply shared between all of the different processes, even though
+they run as different system users. The configuration does not contain any
+sensitive information.
+.. _ExchangeInstallation:
Installation
============
-Before installing a Taler exchange, please make sure that your
-system does not have swap space enabled. Swap space is a security
-risk that Taler does not try to mitigate against.
+Before installing a Taler exchange, please make sure that your system does not
+have swap space enabled. Swap space is a security risk that Taler does not
+try to mitigate against.
-Please install the following packages before proceeding with the
-exchange compilation.
+We recommend the setup of offline signing keys to be done on a second machine that
+does not have Internet access.
-.. include:: frags/list-of-dependencies.rst
+In this guide's shell-session fragments, the command prompt shows two pieces
+of information:
-- GNU Taler exchange (from `download directory <http://ftpmirror.gnu.org/taler/>`__,
- see `release announcement <https://mail.gnu.org/archive/cgi-bin/namazu.cgi?query=taler&idxname=info-gnu&max=20&result=normal&sort=date:late>`__)
+* Who is performing the command
+ (``$user`` vs ``root``, and ending character ``$`` vs ``#``).
+* Host where the command is supposed to be executed
+ (``exchange-offline`` vs ``exchange-online``).
+ It is possible to do the entire setup on one machine,
+ but we do not recommend this for security reasons.
+
+Before you start
+----------------
+
+To deploy this with a real bank, you need:
+
+ * IBAN of the bank account to use
+ * BIC of the bank
+ * EBICS host, user and partner IDs
+
+Information to write down during the installation:
+
+ * LibEuFin Nexus superuser password
+ * Taler facade base URL
+ * exchange Nexus username and password
-Except for the last two, these are available in most GNU/Linux
-distributions and should just be installed using the respective package
-manager.
Installing from source
@@ -307,10 +353,29 @@ Installing from source
The following instructions will show how to install libgnunetutil and
the GNU Taler exchange from source.
+The package sources can be find in our
+`download directory <http://ftpmirror.gnu.org/taler/>`__.
+
+.. include:: frags/semver.rst
+
+First, the following packages need to be installed before we can compile the
+backend:
+
+.. include:: frags/list-of-dependencies.rst
+
.. include:: frags/installing-gnunet.rst
+.. include:: frags/install-before-check.rst
+
+There is no need to actually run a GNUnet peer to use the Taler merchant
+backend -- all the merchant needs from GNUnet is a number of headers and
+libraries!
+
.. include:: frags/installing-taler-exchange.rst
+.. include:: frags/install-before-check.rst
+
+
Installing the GNU Taler binary packages on Debian
--------------------------------------------------
@@ -319,9 +384,9 @@ Installing the GNU Taler binary packages on Debian
To install the Taler exchange, you can now simply run:
-.. code-block:: console
+.. code-block:: shell-session
- # apt install -t sid taler-exchange
+ [root@exchange-online]# apt install taler-exchange
Note that the package does not perform any configuration work except for
setting up the various users and the systemd service scripts. You still must
@@ -329,9 +394,17 @@ configure at least the database, HTTP reverse proxy (typically with TLS
certificates), denomination and fee structure, bank account, auditor(s),
offline signing and the terms of service.
-Sample configuration files for the HTTP reverse proxy can be found in
-``/etc/taler-exchange/``.
+On the offline system, you should run at least:
+
+.. code-block:: shell-session
+
+ [root@exchange-offline]# apt install taler-exchange-offline
+
+
+Installing the GNU Taler binary packages on Trisquel
+----------------------------------------------------
+.. include:: frags/installing-trisquel.rst
Installing the GNU Taler binary packages on Ubuntu
--------------------------------------------------
@@ -340,9 +413,9 @@ Installing the GNU Taler binary packages on Ubuntu
To install the Taler exchange, you can now simply run:
-.. code-block:: console
+.. code-block:: shell-session
- # apt install -t focal-fossa taler-exchange
+ [root@exchange-online]# apt install taler-exchange
Note that the package does not perform any configuration work except for
setting up the various users and the systemd service scripts. You still must
@@ -350,136 +423,244 @@ configure at least the database, HTTP reverse proxy (typically with TLS
certificates), denomination and fee structure, bank account, auditor(s),
offline signing and the terms of service.
-Sample configuration files for the HTTP reverse proxy can be found in
-``/etc/taler-exchange/``.
+On the offline system, you should run at least:
+.. code-block:: shell-session
-Configuration
-=============
+ [root@exchange-offline]# apt install taler-exchange-offline
-This chapter provides an overview of the exchange configuration. Or at
-least eventually will do so, for now it is a somewhat wild description
-of some of the options.
+Services, users, groups and file system hierarchy
+-------------------------------------------------
-.. include:: frags/configuration-format.rst
+The *taler-exchange* package will create several system users
+to compartmentalize different parts of the system:
+* ``taler-exchange-httpd``: runs the HTTP daemon with the core business logic.
+* ``taler-exchange-secmod-rsa``: manages the RSA private online signing keys.
+* ``taler-exchange-secmod-cs``: manages the CS private online signing keys.
+* ``taler-exchange-secmod-eddsa``: manages the EdDSA private online signing keys.
+* ``taler-exchange-closer``: closes idle reserves by triggering wire transfers that refund the originator.
+* ``taler-exchange-aggregator``: aggregates deposits into larger wire transfer requests.
+* ``taler-exchange-transfer``: performs wire transfers with the bank (via LibEuFin/Nexus).
+* ``taler-exchange-wirewatch``: checks for incoming wire transfers with the bank (via LibEuFin/Nexus).
+* ``postgres``: runs the PostgreSQL database (from *postgresql* package).
+* ``www-data``: runs the frontend HTTPS service with the TLS keys (from *nginx* package).
-.. _Using-taler_002dconfig-exchange:
+.. note::
-.. include:: frags/using-taler-config.rst
+ The *taler-merchant* package additionally creates a ``taler-merchant-httpd`` user
+ to run the HTTP daemon with the merchant business logic.
-.. _Keying:
+The exchange setup uses the following system groups:
-Keying
-------
+* ``taler-exchange-db``: group for all Taler users with direct database access, specifically taler-exchange-httpd, taler-exchange-wirewatch, taler-exchange-closer and taler-exchange-aggregator.
+* ``taler-exchange-secmod``: group for processes with access to online signing keys; this group must have four users: taler-exchange-secmod-rsa, taler-exchange-secmod-cs, taler-exchange-secmod-eddsa and taler-exchange-httpd.
+* ``taler-exchange-offline``: group for the access to the offline private key (only used on the offline host and not used on the online system).
-The exchange works with four types of keys:
-- master key (kept offline)
+The package will deploy systemd service files in
+``/usr/lib/systemd/system/`` for the various components:
- To create a master key, use:
+* ``taler-exchange-aggregator.service``: service that schedules wire transfers
+ which combine multiple deposits to the same merchant.
+* ``taler-exchange-closer.service``: service that watches for reserves that have been abandoned and schedules wire transfers to send the money back to the originator.
+* ``taler-exchange-httpd.service``: main Taler exchange logic with the public REST API.
+* ``taler-exchange-httpd.socket``: systemd socket activation for the Taler exchange HTTP daemon.
+* ``taler-exchange-secmod-eddsa.service``: software security module for making EdDSA signatures.
+* ``taler-exchange-secmod-rsa.service``: software security module for making RSA signatures.
+* ``taler-exchange-secmod-cs.service``: software security module for making CS signatures.
+* ``taler-exchange-transfer.service``: service that triggers outgoing wire transfers (pays merchants).
+* ``taler-exchange-wirewatch.service``: service that watches for incoming wire transfers (first step of withdraw).
+* ``taler-exchange.target``: Main target for the Taler exchange to be operational.
- .. code-block:: console
- $ taler-exchange-offline setup
+The deployment creates the following key locations in the system:
-- sign keys (signs normal messages from the exchange)
+* ``/etc/taler/``: configuration files.
+* ``/run/taler/``: contains the UNIX domain sockets for inter-process communication (IPC).
+* ``/var/lib/taler/``: serves as the $HOME for all Taler users and contains sub-directories
+ with the private keys; which keys are stored here depends on the host:
-- denomination keys (signs electronic coins, see section Coins)
+ * online system: exchange-secmod-eddsa, exchange-secmod-cs and exchange-secmod-rsa keys.
+ * offline system: exchange-offline keys.
-- security module keys (signs sign keys and denomination keys)
-Additionally, the exchange is sometimes concerned with the auditor's public
-key (to verify messages signed by auditors approved by the exchange operator)
-and the merchant's public key (to verify refunds are authorized by the
-merchant).
+Configuration Fundamentals
+==========================
+This chapter provides fundamental details about the exchange configuration.
-Key options include:
+The configuration for all Taler components uses a single configuration file
+as entry point: ``/etc/taler/taler.conf``.
-- ``[exchange-offline/MASTER_PRIV_FILE]``: Path to the exchange’s master private file. Only needs to be provided on the offline system where the ``taler-exchange-offline`` command is used.
+System defaults are automatically loaded from files in
+``/usr/share/taler/config.d``. These default files should never be modified.
-- ``[exchange/MASTER_PUBLIC_KEY]``: Must specify the exchange’s master public key. Needed for the exchange to verify information signed by the offline system.
+The default configuration ``taler.conf`` configuration file also includes all
+configuration files in ``/etc/taler/conf.d``. The settings from files in
+``conf.d`` are only relevant to particular components of Taler, while
+``taler.conf`` contains settings that affect all components.
-.. _Serving:
+The directory ``/etc/taler/secrets`` contains configuration file snippets with
+values that should only be readable to certain users. They are included with the ``@inline-secret@``
+directive and should end with ``.secret.conf``.
-Serving
--------
+To view the entire configuration annotated with the source of each configuration option, you
+can use the ``taler-config`` helper:
-The exchange can serve HTTP over both TCP and UNIX domain socket.
-The following options are to be configured in the section ``[exchange]``:
+.. code-block:: shell-session
-- ``SERVE``: Must be set to ``tcp`` to serve HTTP over TCP, or ``unix`` to serve
- HTTP over a UNIX domain socket.
+ [root@exchange-online]# taler-config --diagnostics
+ < ... annotated, full configuration ... >
-- ``PORT``: Set to the TCP port to listen on if ``SERVE`` is ``tcp``.
+.. warning::
-- ``UNIXPATH``: Set to the UNIX domain socket path to listen on if ``SERVE`` is
- ``unix``.
+ While ``taler-config`` also supports rewriting configuration files, we strongly
+ recommend to edit configuration files manually, as ``taler-config`` does not
+ preserve comments and, by default, rewrites ``/etc/taler/taler.conf``.
+
+
+.. include:: frags/configuration-format.rst
-- ``UNIXPATH_MODE``: Number giving the mode with the access permission mask
- for the ``UNIXPATH`` (i.e. 660 = ``rw-rw---``).
-.. _Currency:
+Exchange Database Setup
+=======================
-Currency
---------
+The access credentials for the exchange's database are configured in
+``/etc/taler/secrets/exchange-db.secret.conf``. Currently, only PostgreSQL is
+supported as a database backend.
-The exchange supports only one currency. This data is set under the
-respective option ``CURRENCY`` in section ``[taler]``.
+The following users must have access to the exchange database:
+
+* taler-exchange-httpd
+* taler-exchange-wire
+* taler-exchange-aggregator
+* taler-exchange-closer
+
+These users are all in the taler-exchange-db group, and the
+``exchange-db.secret.conf`` should be only readable by users in
+this group.
+
+.. note::
-.. _Database:
+ The **taler-exchange-dbconfig** tool can be used to automate the database
+ setup. When using the Debian/Ubuntu packages, the users should already have
+ been created, so you can just run the tool without any arguments and should
+ have a working database configuration. The rest of this section only
+ explains what the **taler-exchange-dbconfig** shell script fully automates.
-Database
---------
+To create a database for the Taler exchange on the local system, run:
-The option ``DB`` in section ``[exchange]`` gets the database backend’s name the
-exchange is going to use. So far, only ``db = postgres`` is supported. After
-choosing the backend, it is mandatory to supply the connection string
-(namely, the database name). This is possible in two ways:
+.. code-block:: shell-session
-- via an environment variable: ``TALER_EXCHANGEDB_POSTGRES_CONFIG``.
+ [root@exchange-online]# su - postgres
+ [postgres@exchange-online]# createuser taler-exchange-httpd
+ [postgres@exchange-online]# createuser taler-exchange-wire
+ [postgres@exchange-online]# createuser taler-exchange-aggregator
+ [postgres@exchange-online]# createuser taler-exchange-closer
+ [postgres@exchange-online]# createdb -O taler-exchange-httpd taler-exchange
+ [postgres@exchange-online]# exit
-- via configuration option ``CONFIG``, under section ``[exchangedb-$BACKEND]``.
- For example, the demo exchange is configured as follows:
+This will create a ``taler-exchange`` database owned by the
+``taler-exchange-httpd`` user. We will use that user later to perform
+database maintenance operations.
+
+
+Assuming the above database setup, the database credentials to configure
+in the configuration file would simply be:
.. code-block:: ini
+ :caption: /etc/taler/secrets/exchange-db.secret.conf
- [exchange]
- ...
- DB = postgres
- ...
+ [exchange]
+ DB = postgres
- [exchangedb-postgres]
- CONFIG = postgres:///talerdemo
+ [exchangedb-postgres]
+ CONFIG=postgres:///taler-exchange
-Given this database configuration, the database can be initialized using:
+If the database is run on a different host, please follow the instructions
+from the PostgreSQL manual for configuring remote access.
-.. code-block:: console
+After configuring the database credentials, the exchange database needs
+to be initialized with the following command:
- $ taler-exchange-dbinit
+.. code-block:: shell-session
+
+ [root@exchange-online]# sudo -u taler-exchange-httpd taler-exchange-dbinit
+
+ ..note::
+
+ To run this command, the user must have ``CREATE TABLE``, ``CREATE
+ INDEX``, ``ALTER TABLE`` and (in the future possibly even) ``DROP TABLE``
+ permissions. Those permissions are only required for this step (which may
+ have to be repeated when upgrading a deployment). Afterwards, during
+ normal operation, permissions to ``CREATE`` or ``ALTER`` tables are not
+ required by any of the Taler exchange processes and thus should not be
+ granted. For more information, see
+ :doc:`manpages/taler-exchange-dbinit.1`.
+
+Finally we need to grant the other accounts limited access:
+
+.. code-block:: shell-session
+
+ [root@exchange-online]# sudo -u taler-exchange-httpd bash
+ [taler-exchange-httpd@exchange-online]# echo 'GRANT SELECT,INSERT,UPDATE ON ALL TABLES IN SCHEMA exchange TO "taler-exchange-aggregator";' \
+ | psql taler-exchange
+ [taler-exchange-httpd@exchange-online]# echo 'GRANT SELECT,INSERT,UPDATE ON ALL TABLES IN SCHEMA exchange TO "taler-exchange-closer";' \
+ | psql taler-exchange
+ [taler-exchange-httpd@exchange-online]# echo 'GRANT SELECT,INSERT,UPDATE ON ALL TABLES IN SCHEMA exchange TO "taler-exchange-wire";' \
+ | psql taler-exchange
+ [taler-exchange-httpd@exchange-online]# echo 'GRANT USAGE ON ALL SEQUENCES IN SCHEMA exchange TO "taler-exchange-aggregator";' \
+ | psql taler-exchange
+ [taler-exchange-httpd@exchange-online]# echo 'GRANT USAGE ON ALL SEQUENCES IN SCHEMA exchange TO "taler-exchange-closer";' \
+ | psql taler-exchange
+ [taler-exchange-httpd@exchange-online]# echo 'GRANT USAGE ON ALL SEQUENCES IN SCHEMA exchange TO "taler-exchange-wire";' \
+ | psql taler-exchange
+ [taler-exchange-httpd@exchange-online]# exit
+
+.. note::
+
+ The above instructions for changing database permissions only work *after*
+ having initialized the database with ``taler-exchange-dbinit``, as
+ the tables need to exist before permissions can be granted on them. The
+ ``taler-exchange-dbinit`` tool cannot setup these permissions, as it
+ does not know which users will be used for which processes.
+
+
+Basic Setup: Currency, Denominations and Keys
+=============================================
+
+A Taler exchange only supports a single currency. The currency
+and the smallest currency unit supported by the bank system
+must be specified in ``/etc/taler/taler.conf``.
+
+.. code-block:: ini
+ :caption: /etc/taler/taler.conf
+
+ [taler]
+ CURRENCY = EUR
+ CURRENCY_ROUND_UNIT = EUR:0.01
-Note that to run this command, the user must have ``CREATE TABLE``, ``CREATE
-INDEX``, ``ALTER TABLE`` and (in the future possibly even) ``DROP TABLE``
-permissions. Those permissions are only required for this step (which may
-have to be repeated when upgrading a deployment). Afterwards, during normal
-operation, permissions to ``CREATE`` or ``ALTER`` tables are not required by
-any of the Taler exchange processes and thus should not be granted.
-For more information, see :doc:`manpages/taler-exchange-dbinit.1`.
+ # ... rest of file ...
-Commands, like ``taler-exchange-dbinit``, that support the ``-l LOGFILE``
-command-line option, send logging output to standard error by default.
+.. warning::
-.. _Coins-denomination-keys:
+ When editing ``/etc/taler/taler.conf``, take care to not accidentally remove
+ the ``@inline-matching@`` directive to include the configuration files in ``conf.d``.
+
+ .. _Coins-denomination-keys:
Coins (denomination keys)
-------------------------
+Next, the electronic cash denominations that the exchange offers must be
+specified.
+
Sections specifying denomination (coin) information start with ``coin_``. By
convention, the name continues with ``$CURRENCY_[$SUBUNIT]_$VALUE_$REVISION``,
i.e. ``[coin_eur_ct_10_0]`` for a 10 cent piece. However, only the ``coin_``
@@ -512,9 +693,16 @@ must then have the following options:
- ``FEE_REFUND``: What does it cost to refund this coin?
Specified using the same format as value.
+- ``CIPHER``: Which cipher to use for this coin? Must be either ``RSA`` or
+ ``CS``.
+
- ``RSA_KEYSIZE``: How many bits should the RSA modulus (product of the two
primes) have for this type of coin.
+- ``AGE_RESTRICTED``: Set to ``YES`` to make this a denomination with support
+ for age restrictions. See age restriction extension below for details.
+ This option is optional and defaults to ``NO``.
+
See :doc:`manpages/taler.conf.5` for information on *duration* values
(i.e. ``DURATION_WITHDRAW`` and ``DURATION_SPEND`` above,
and ``OVERLAP_DURATION`` and ``DURATION`` below).
@@ -543,6 +731,23 @@ Additionally, there are two global configuration options of note:
for the exchange and the crypto helpers. We recommend pointing both users
to the same configuration file!
+The ``taler-wallet-cli`` has a helper command that generates a
+reasonable denomination structure.
+
+.. code-block:: shell-session
+
+ [root@exchange-online]# taler-wallet-cli deployment gen-coin-config \
+ --min-amount EUR:0.01 \
+ --max-amount EUR:100 \
+ > /etc/taler/conf.d/exchange-coins.conf
+
+You can manually review and edit the generated configuration file. The main
+change that is possibly required is updating the various fees. Note that you
+MUST NOT edit a coin configuration section after the initial setup. If you
+must ``change`` the values, you must instead create a new section with a
+different unique name (still with the ``coin-`` prefix) and comment out or
+remove the existing section. Do take care to not introduce the name of the
+disabled section again in the future.
.. _Sign-keys:
@@ -574,64 +779,81 @@ There are three global configuration options of note for sign keys:
delayed.
-Terms of Service
-----------------
+.. _OfflineConfiguration:
-The exchange has an endpoint "/terms" to return the terms of service
-(in legal language) of the exchange operator. The wallet will show
-those terms of service to the user when the user is first withdrawing
-coins. Terms of service are optional for experimental deployments,
-if none are configured, the exchange will return a simple statement
-saying that there are no terms of service available.
-
-To configure the terms of service response, there are two options
-in the ``[exchange]`` section:
-
-- ``TERMS_ETAG``: The current "Etag" to return for the terms of service.
- This value must be changed whenever the terms of service are
- updated. A common value to use would be a version number.
- Note that if you change the ``TERMS_ETAG``, you MUST also provide
- the respective files in ``TERMS_DIR`` (see below).
-- ``TERMS_DIR``: The directory that contains the terms of service.
- The files in the directory must be readable to the exchange
- process.
-
-The ``TERMS_DIR`` directory structure must follow a particular layout.
-First, inside of ``TERMS_DIR``, there should be sub-directories using
-two-letter language codes like "en", "de", or "jp". Each of these
-directories would then hold translations of the current terms of
-service into the respective language. Empty directories are
-permitted in case translations are not available.
-
-Then, inside each language directory, files with the name of the
-value set as the ``TERMS_ETAG`` must be provided. The extension of
-each of the files should be typical for the respective mime type.
-The set of supported mime types is currently hard-coded in the
-exchange, and includes HTML, PDF and TXT files. If other files are
-present, the exchange may show a warning on startup.
-
-Example
-^^^^^^^
-
-A sample file structure for a ``TERMS_ETAG`` of "v1" would be:
-
-- TERMS_DIR/en/v1.txt
-- TERMS_DIR/en/v1.html
-- TERMS_DIR/en/v1.pdf
-- TERMS_DIR/de/v1.txt
-- TERMS_DIR/de/v1.html
-- TERMS_DIR/de/v1.pdf
-- TERMS_DIR/fr/v1.pdf
-
-If the user requests an HTML format with language preferences "fr" followed by "en",
-the exchange would return ``TERMS_DIR/en/v1.html`` lacking an HTML version in
-French.
-
-
-.. _Bank-account:
-
-Bank account
-------------
+Setting up the offline signing key
+----------------------------------
+
+Before launching an exchange, the offline signing (master) key must be
+generated and set in the configuration. The offline signing keys of the
+exchange should be stored on a different machine. The responsibilities of
+this offline signing machine are:
+
+* Generation of the exchange's offline master signing key.
+* Secure storage of the exchange's offline master signing key.
+* Generation of certificates (signed with the offline master signing key) that will be imported by the exchange.
+* Revocation of keys when the online system was compromised or is being terminated
+
+
+Configuration file options related to the master key are:
+
+- ``[exchange-offline/MASTER_PRIV_FILE]``: Path to the exchange’s master
+ private file. Only needs to be provided on the offline system where the
+ ``taler-exchange-offline`` command is used. The default value is usually
+ fine and does not require adjustment.
+
+- ``[exchange/MASTER_PUBLIC_KEY]``: Must specify the exchange’s master public
+ key. Needed for the exchange to verify information signed by the offline
+ system. This value must almost always be set explicitly by hand.
+
+
+
+.. code-block:: shell-session
+
+ [root@exchange-offline]# taler-exchange-offline setup
+ < ... prints the exchange master public key >
+
+The public key printed as the output of this command must be put into the
+configuration of the online machine:
+
+.. code-block:: ini
+ :caption: /etc/taler/conf.d/exchange-business.conf
+
+ [exchange]
+ MASTER_PUBLIC_KEY = YE6Q6TR1ED...
+
+ # ... rest of file ...
+
+
+Wire Gateway Setup
+==================
+
+The :ref:`Taler Wire Gateway <taler-wire-gateway-http-api>` is an API that
+connects the Taler exchange to the underlying core banking system. There are
+several implementations of wire gateways:
+
+ * `Project deploymerization <https://git.taler.net/depolymerization.git>`_ implements a wire gateway on top of Bitcoin or Ethereum
+ * The :ref:`libeufin-bank <libeufin-bank>` provides a wire gateway interface on top of a regional currency bank
+ * The **taler-fakebank-run** command is an in-memory bank simulator with a wire gateway interface for testing
+
+.. FIXME :ref:`libeufin-nexus <libeufin-nexus>` is an implementation of the Wire Gateway API for the EBICS protocol. Add to list above once nexus implements the TWG directly!
+
+Before continuing, you need to decide which wire gateway you want to use,
+and install and configure it on your system. Afterwards, you need to
+have two key pieces of information from that setup:
+
+ * The username and password to access the exchange's account in the system.
+ * The ``payto://`` URI of that account (see `RFC 8905 <https://www.rfc-editor.org/rfc/rfc8905>`_).
+
+.. _exchange-bank-account-configuration:
+
+Exchange Bank Account Configuration
+-----------------------------------
+
+An exchange must be configured with the right settings to access its bank
+account via a :ref:`Taler wire gateway <taler-wire-gateway-http-api>`. An
+exchange can be configured to use multiple bank accounts by using multiple
+wire gateways. Typically only one wire gateway is used.
To configure a bank account in Taler, we need to furnish two pieces of
information:
@@ -642,8 +864,8 @@ information:
an IBAN or
``payto://x-taler-bank/localhost:8080/2`` for the 2nd bank account a
the Taler bank demonstrator running at ``localhost`` on port 8080.
- The first part of the URI following ``payto://`` (“iban” or
- “x-taler-bank”) is called the wire method.
+ The first part of the URI following ``payto://`` (``iban`` or
+ ``x-taler-bank``) is called the wire method.
- The ``taler-exchange-wirewatch`` and ``taler-exchange-transfer``
tools needs to be provided resources for authentication
@@ -651,103 +873,380 @@ information:
authentication information is currently a username and password
for HTTP basic authentication.
+
+Each Taler wire gateway is configured in a configuration section that follows
+the pattern ``exchange-account-$id``, where ``$id`` is an internal identifier
+for the bank account accessed by the exchange. The basic information for an
+account should be put in ``/etc/taler/conf.d/exchange-business.conf``. The
+secret credentials to access the Taler Wire Gateway API should be put into a
+corresponding ``exchange-accountcredentials-$id`` section in
+``/etc/taler/secrets/exchange-accountcredentials.conf``. The latter file
+should be only readable for the ``taler-exchange-wire`` user. Only the
+``taler-exchange-wirewatch`` and ``taler-exchange-transfer`` services should
+run as the ``taler-exchange-wire`` user. Other exchange processes do not need
+to have access to the account credentials.
+
You can configure multiple accounts for an exchange by creating sections
-starting with “exchange-account-” for the section name. You can ENABLE for
-each account whether it should be used, and for what (incoming or outgoing
-wire transfers):
+starting with ``exchange-account-`` for the section name. You must specify
+``ENABLE_``-settings for each account whether it should be used, and for what
+(incoming or outgoing wire transfers):
.. code-block:: ini
+ :caption: /etc/taler/conf.d/exchange-business.conf
- [exchange-account-1]
- # With x-taler-bank (say for PyBank)
- PAYTO_URI = "payto://x-taler-bank/bank.demo.taler.net/Exchange"
+ [exchange-account-1]
+ # Account identifier in the form of an RFC-8905 payto:// URI.
+ # For SEPA, looks like payto://iban/$IBAN?receiver-name=$NAME
+ # Make sure to URL-encode spaces in $NAME!
+ #
+ # With x-taler-bank (for Fakebank)
+ # PAYTO_URI = "payto://x-taler-bank/bank.demo.taler.net/Exchange?receiver-name=exop"
+ #
+ # Example using IBAN (for use with LibEuFin)
+ PAYTO_URI = "payto://iban/CH9300762011623852957?receiver=name=exop"
- # Example using IBAN (for use with LibEuFin)
- # PAYTO_URI = "payto://iban/CH9300762011623852957"
+ # URL for talking to the bank wire the wire API.
+ WIRE_GATEWAY_URL = https://bank.demo.taler.net/taler-wire-gateway/Exchange
- # URL for talking to the bank wire the wire API.
- WIRE_GATEWAY_URL = https://bank.demo.taler.net/taler-wire-gateway/Exchange
+ # Use for exchange-aggregator (outgoing transfers)
+ ENABLE_DEBIT = YES
+ # Use for exchange-wirewatch (and listed in /wire)
+ ENABLE_CREDIT = YES
- # Use for exchange-aggregator (outgoing transfers)
- ENABLE_DEBIT = YES
- # Use for exchange-wirewatch (and listed in /wire)
- ENABLE_CREDIT = YES
+ @inline-secret@ exchange-accountcredentials-1 ../secrets/exchange-accountcredentials.secret.conf
- # Authentication options for exchange bank account go here.
- # (Next sections have examples of authentication mechanisms)
- WIRE_GATEWAY_AUTH_METHOD = basic
- USERNAME = exchange
- PASSWORD = super-secure
+.. code-block:: ini
+ :caption: /etc/taler/secrets/exchange-accountcredentials.secret.conf
-The command line tool ``taler-exchange-offline`` must be used to
-sign the ``payto://`` URI in a way suitable to convince wallets that
-this is the correct address to wire funds to.
-For example, the utility may be invoked as
-follows to enable a wire account:
+ [exchange-accountcredentials-1]
-.. code-block:: console
+ # LibEuFin expects basic auth.
+ WIRE_GATEWAY_AUTH_METHOD = basic
- $ taler-exchange-offline enable-account payto://iban/CH9300762011623852957
+ # Username and password to access the Taler wire gateway.
+ USERNAME = ...
+ PASSWORD = ...
-The resulting JSON output must be uploaded to the exchange using
-``taler-exchange-offline upload``.
-For details, see :doc:`manpages/taler-exchange-offline.1`.
+ # Base URL of the Taler wire gateway.
+ WIRE_GATEWAY_URL = ...
-.. _Wire-fee-structure:
+Such a wire gateway configuration can be tested with the following commands:
-Wire fee structure
-^^^^^^^^^^^^^^^^^^
+.. code-block:: shell-session
-.. index:: wire fee
-.. index:: fee
+ [root@exchange-online]# taler-exchange-wire-gateway-client \
+ --section exchange-accountcredentials-1 --debit-history
+ [root@exchange-online]# taler-exchange-wire-gateway-client \
+ --section exchange-accountcredentials-1 --credit-history
-For each wire method (“sepa” or “x-taler-wire”) the
-exchange must know about applicable wire fees. This is also done
-using the ``taler-exchange-offline`` tool:
+On success, you will see some of your account's transaction history (or an
+empty history), while on failure you should see an error message.
-.. code-block:: console
+.. _LegalSetup:
- $ taler-exchange-offline wire-fee iban 2040 EUR:0.05 EUR:0.10
+Legal Setup
+===========
-The above sets the wire fees for wire transfers involving ``iban`` accounts
-(in Euros) in the year 2040 to 5 cents (wire fee) and 10 cents (closing fee).
-The tool only supports setting fees that applies for the entire calendar year.
+This chapter describes how to setup certain legal aspects of a GNU Taler
+exchange. Users that just want to set up an exchange as an experiment without
+legal requirements can safely skip these steps.
-We recommend provisioning an exchange with wire fees at least for the next two
-years. Note that once the fees have been set for a year, they cannot be
-changed (basically, by signing the fees the exchange makes a legally binding
-offer to the customers).
-.. index:: maintenance
-.. note::
- Provisioning future wire fees, like provisioning future denomination
- and signing keys, are key regular maintenance procedures for every
- exchange operator. We recommend setting automated reminders for
- this maintenance activity!
+Legal conditions for using the service
+--------------------------------------
+.. include:: frags/legal.rst
-.. _Auditor-configuration:
-Auditor configuration
+KYC Configuration
+=================
+
+To legally operate, Taler exchange operators may have to comply with KYC
+regulation that requires financial institutions to identify parties involved
+in transactions at certain points.
+
+Taler permits an exchange to require KYC data under the following circumstances:
+
+ * Customer withdraws money over a threshold
+ * Wallet receives (via refunds) money resulting in a balance over a threshold
+ * Wallet receives money via P2P payments over a threshold
+ * Merchant receives money over a threshold
+ * Reserve is "opened" for invoicing (**planned feature**)
+
+Any of the above requests can trigger the KYC process,
+which can be illustrated as follows:
+
+.. image:: images/kyc-process.png
+
+At the end of the KYC process, the wallet re-tries the
+original request, and assuming KYC was successful, the
+request should then succeed.
+
+
+Taler KYC Terminology
---------------------
-The exchange must be informed about any auditor that is expected to provision
-it with auditor signatures. This is also done using the
-``taler-exchange-offline`` tool on the offline system. First, the auditor
-must be configured and provide the exchange operator with its public key and
-the URL of it's REST API. The exchange operator also needs a human-readable
-name that may be shown to users to identify the auditor. Given this
-information, the exchange operator can enable the auditor:
+* **Check**: A check establishes a particular attribute of a user, such as
+ their name based on an ID document and lifeness, mailing address, phone
+ number, taxpayer identity, etc.
-.. code-block:: console
+* **Type of operation**: The operation type determines which Taler-specific
+ operation has triggered the KYC requirement. We support four types of
+ operation: withdraw (by customer), deposit (by merchant), P2P receive (by
+ wallet) and (high) wallet balance.
+
+* **Condition**: A condition specifies when KYC is required. Conditions
+ include the *type of operation*, a threshold amount (e.g. above EUR:1000)
+ and possibly a time period (e.g. over the last month).
+
+* **Cost**: Metric for the business expense for a KYC check at a certain
+ *provider*. Not in any currency, costs are simply relative and non-negative
+ values. Costs are considered when multiple choices are allowed by the
+ *configuration*.
+
+* **Expiration**: KYC legitimizations may be outdated. Expiration rules
+ determine when *checks* have to be performed again.
+
+* **Legitimization rules**: The legitimization rules determine under which
+ *conditions* which *checks* must be performend and the *expiration* time
+ period for the *checks*.
+
+* **Logic**: Logic refers to a specific bit of code (realized as an exchange
+ plugin) that enables the interaction with a specific *provider*. Logic
+ typically requires configuration for access control (such as an
+ authorization token) and possibly the endpoint of the specific *provider*
+ implementing the respective API.
+
+* **Provider**: A provider performs a specific set of *checks* at a certain
+ *cost*. Interaction with a provider is performed by provider-specific
+ *logic*.
+
+
+KYC Configuration Options
+-------------------------
+
+The KYC configuration determines the *legitimization rules*, and specifies
+which providers offer which *checks* at what *cost*.
+
+The configuration specifies a set of providers, one per configuration section. The names of the configuration
+sections must being with ``kyc-proider-`` followed by
+an arbitrary ``$PROVIDER_ID``:
+
+.. code-block:: ini
+ :caption: /etc/taler/conf.d/exchange-kyc-providers.conf
+
+ [kyc-provider-$PROVIDER_ID]
+ # How expensive is it to use this provider?
+ # Used to pick the cheapest provider possible.
+ COST = 42
+ # Which plugin is responsible for this provider?
+ # Choices include "oauth2", "kycaid" and "persona".
+ LOGIC = oauth2
+ # Which type of user does this provider handle?
+ # Either INDIVIDUAL or BUSINESS.
+ USER_TYPE = INDIVIDUAL
+ # Which checks does this provider provide?
+ # List of strings, no specific semantics.
+ PROVIDED_CHECKS = SMS GOVID PHOTO
+ # Plus additional logic-specific options, e.g.:
+ AUTHORIZATION_TOKEN = superdupersecret
+ FORM_ID = business_legi_form
+ # How long is the check considered valid?
+ EXPIRATION = 3650d
+
+The configuration also must specify a set of legitimization requirements, again one
+per configuration section:
+
+.. code-block:: ini
+ :caption: /etc/taler/conf.d/exchange-kyc-rules.conf
+
+ [kyc-legitimization-$RULE_NAME]
+ # Operation that triggers this legitimization.
+ # Must be one of WITHDRAW, DEPOSIT, P2P-RECEIVE
+ # or WALLET-BALANCE.
+ OPERATION_TYPE = WITHDRAW
+ # Required checks to be performed.
+ # List of strings, must individually match the
+ # strings in one or more provider's PROVIDED_CHECKS.
+ REQUIRED_CHECKS = SMS GOVID
+ # Threshold amount above which the legitimization is
+ # triggered. The total must be exceeded in the given
+ # timeframe.
+ THRESHOLD = KUDOS:100
+ # Timeframe over which the amount to be compared to
+ # the THRESHOLD is calculated. Can be 'forever'.
+ # Ignored for WALLET-BALANCE.
+ TIMEFRAME = 30d
+
+
+OAuth 2.0 specifics
+-------------------
+
+In terms of configuration, the OAuth 2.0 logic requires the respective client
+credentials to be configured apriori to enable access to the legitimization
+service. The OAuth 2.0 configuration options are:
+
+.. code-block:: ini
+ :caption: /etc/taler/conf.d/exchange-oauth2.conf
+
+ [kyc-provider-example-oauth2]
+ LOGIC = oauth2
+ # (generic options omitted)
+ # How long is the KYC check valid?
+ KYC_OAUTH2_VALIDITY = forever
+
+ # URL to which we redirect the user for the login process
+ KYC_OAUTH2_AUTHORIZE_URL = "http://kyc.example.com/authorize"
+ # URL where we POST the user's authentication information
+ KYC_OAUTH2_TOKEN_URL = "http://kyc.example.com/token"
+ # URL of the user info access point.
+ KYC_OAUTH2_INFO_URL = "http://kyc.example.com/info"
+
+ # Where does the client get redirected upon completion?
+ KYC_OAUTH2_POST_URL = "http://example.com/thank-you"
+
+ # For authentication to the OAuth2.0 service
+ KYC_OAUTH2_CLIENT_ID = testcase
+ KYC_OAUTH2_CLIENT_SECRET = password
+
+ # Mustach template that converts OAuth2.0 data about the user
+ # into GNU Taler standardized attribute data.
+ KYC_OAUTH2_CONVERTER_HELPER = taler-exchange-kyc-oauth2-challenger.sh
+
+The converter helper is expected to be customized to the selected OAuth2.0
+service: different services may return different details about the user or
+business, hence there cannot be a universal converter for all purposes. The
+default shell script uses the ``jq`` tool to convert the JSON returned by the
+service into the KYC attributes (also in JSON) expected by the exchange. The
+script will need to be adjusted based on the attributes collected by the
+specific backend.
+
+The Challenger service for address validation supports OAuth2.0, but does not
+have a static AUTHORIZE_URL. Instead, the AUTHORIZE_URL must be enabled by the client
+using a special authenticated request to the Challenger's ``/setup`` endpoint.
+The exchange supports this by appending ``#setup`` to the AUTHORIZE_URL (note
+that fragments are illegal in OAuth2.0 URLs). Be careful to quote the URL,
+as ``#`` is otherwise interpreted as the beginning of a comment by the
+configuration file syntax.
+
+.. code-block:: ini
+ :caption: /etc/taler/conf.d/exchange-challenger-oauth2.conf
+
+ [kyc-provider-challenger-oauth2]
+ LOGIC = oauth2
+ KYC_OAUTH2_AUTHORIZE_URL = "http://challenger.example.com/authorize/#setup"
+ KYC_OAUTH2_TOKEN_URL = "http://challenger.example.com/token"
+ KYC_OAUTH2_INFO_URL = "http://challenger.example.com/info"
+
+When using OAuth 2.0, the *CLIENT REDIRECT URI* must be set to the
+``/kyc-proof/$PROVIDER_SECTION`` endpoint. For example, given the
+configuration above and an exchange running on the host
+``exchange.example.com``, the redirect URI would be
+``https://exchange.example.com/kyc-proof/kyc-provider-challenger-oauth2/``.
- $ taler-exchange-offline enable-auditor $PUB_KEY $REST_URL "$AUDITOR_NAME" > auditor.json
-As before, the *auditor.json* file must then be copied from the offline system
-to a system connected to the exchange and there ``uploaded`` to the exchange.
+Persona specifics
+-----------------
+
+We use the hosted flow. The Persona endpoints return a ``request-id``, which
+we log for diagnosis.
+
+Persona should be configured to use the ``/kyc-webhook/`` endpoint of the
+exchange to notify the exchange about the completion of KYC processes. The
+webhook is authenticated using a shared secret, which should be in the
+configuration. To use the Persona webhook, you must set the webhook URL in
+the Persona service to ``$EXCHANGE_BASE_URL/kyc-webhook/$SECTION_NAME/`` where
+``$SECTION_NAME`` is the name of the configuration section. You should also
+extract the authentication token for the webhook and put it into the
+configuration as shown above.
+
+
+.. code-block:: ini
+ :caption: /etc/taler/conf.d/exchange-persona.conf
+
+ [kyclogic-persona]
+ # Webhook authorization token. Global for all uses
+ # of the persona provider!
+ WEBHOOK_AUTH_TOKEN = wbhsec_698b5a19-c790-47f6-b396-deb572ec82f9
+
+ [kyc-provider-example-persona]
+ LOGIC = persona
+ # (generic options omitted)
+
+ # How long is the KYC check valid?
+ KYC_PERSONA_VALIDITY = 365d
+
+ # Which subdomain is used for our API?
+ KYC_PERSONA_SUBDOMAIN = taler
+
+ # Authentication token to use.
+ KYC_PERSONA_AUTH_TOKEN = persona_sandbox_42XXXX
+
+ # Form to use.
+ KYC_PERSONA_TEMPLATE_ID = itempl_Uj6Xxxxx
+
+ # Where do we redirect to after KYC finished successfully.
+ KYC_PERSONA_POST_URL = "https://taler.net/kyc-done"
+
+ # Salt to give to requests for idempotency.
+ # Optional.
+ # KYC_PERSONA_SALT = salt
+
+ # Helper to convert JSON with KYC data returned by Persona into GNU Taler
+ # internal format. Should probably always be set to some variant of
+ # "taler-exchange-kyc-persona-converter.sh".
+ KYC_PERSONA_CONVERTER_HELPER = "taler-exchange-kyc-persona-converter.sh"
+
+The converter helper is expected to be customized to the
+selected template: different templates may return different details
+about the user or business, hence there cannot be a universal converter
+for all purposes. The default shell script uses the ``jq`` tool to
+convert the JSON returned by Persona into the KYC attributes (also
+in JSON) expected by the exchange. The script will need to be adjusted
+based on the attributes collected by the specific template.
+
+
+KYC AID specifics
+-----------------
+
+We use the hosted flow.
+
+KYCAID must be configured to use the ``/kyc-webhook/$SECTION_NAME/`` endpoint
+of the exchange to notify the exchange about the completion of KYC processes.
+
+.. code-block:: ini
+ :caption: /etc/taler/conf.d/exchange-kycaid.conf
+
+ [kyc-provider-example-kycaid]
+ LOGIC = kycaid
+ # (generic options omitted)
+
+ # How long is the KYC check valid?
+ KYC_KYCAID_VALIDITY = 365d
+
+ # Authentication token to use.
+ KYC_KYCAID_AUTH_TOKEN = XXX
+
+ # Form to use.
+ KYC_KYCAID_FORM_ID = XXX
+
+ # URL to go to after the process is complete.
+ KYC_KYCAID_POST_URL = "https://taler.net/kyc-done"
+
+ # Script to convert the KYCAID data into the Taler format.
+ KYC_KYCAID_CONVERTER_HELPER = taler-exchange-kyc-kycaid-converter.sh
+
+
+The converter helper is expected to be customized to the selected template:
+different templates may return different details about the user or business,
+hence there cannot be a universal converter for all purposes. The default
+shell script uses the ``jq`` tool to convert the JSON returned by Persona into
+the KYC attributes (also in JSON) expected by the exchange. The script will
+need to be adjusted based on the attributes collected by the specific
+template.
.. _Deployment:
@@ -755,9 +1254,72 @@ to a system connected to the exchange and there ``uploaded`` to the exchange.
Deployment
==========
-This chapter describes how to deploy the exchange once it has been
-configured.
+This chapter describes how to deploy the exchange once the basic installation
+and configuration are completed.
+
+.. _Serving:
+Serving
+-------
+
+The exchange can serve HTTP over both TCP and UNIX domain socket.
+
+The following options are to be configured in the section ``[exchange]``:
+
+- ``SERVE``: Must be set to ``tcp`` to serve HTTP over TCP, or ``unix`` to serve
+ HTTP over a UNIX domain socket.
+
+- ``PORT``: Set to the TCP port to listen on if ``SERVE`` is ``tcp``.
+
+- ``UNIXPATH``: Set to the UNIX domain socket path to listen on if ``SERVE`` is
+ ``unix``.
+
+- ``UNIXPATH_MODE``: Number giving the mode with the access permission mask
+ for the ``UNIXPATH`` (i.e. 660 = ``rw-rw---``). Make sure to set it in such
+ a way that your reverse proxy has permissions to access the UNIX domain
+ socket. The default (660) assumes that the reverse proxy is a member of
+ the group under which the exchange HTTP server is running.
+
+.. _ReverseProxy:
+
+Reverse Proxy Setup
+-------------------
+
+By default, the ``taler-exchange-httpd`` service listens for HTTP connections
+on a UNIX domain socket. To make the service publicly available, a reverse
+proxy such as nginx should be used. We strongly recommend to configure nginx
+to use TLS.
+
+The public URL that the exchange will be served under should
+be put in ``/etc/taler/conf.d/exchange-business.conf`` configuration file.
+
+.. code-block:: ini
+ :caption: /etc/taler/conf.d/exchange-business.conf
+
+ [exchange]
+ BASE_URL = https://example.com/
+
+ # ... rest of file ...
+
+The ``taler-exchange`` package ships with a sample configuration that can be
+enabled in nginx:
+
+.. code-block:: shell-session
+
+ [root@exchange-online]# vim /etc/nginx/sites-available/taler-exchange
+ < ... customize configuration ... >
+ [root@exchange-online]# ln -s /etc/nginx/sites-available/taler-exchange \
+ /etc/nginx/sites-enabled/taler-exchange
+ [root@exchange-online]# systemctl reload nginx
+
+Note that the reverse proxy must set a HTTP ``X-Forwarded-Host`` header to
+refer to the hostname used by nginx and a HTTP ``X-Forwarded-Proto`` header to
+inform the exchange whether the external protocol was ``http`` or ``https``.
+Thus, depending on your setup, you will likely have to edit those parts of the
+provided ``taler-exchange`` configuration file.
+
+With this last step, we are finally ready to launch the
+main exchange process.
.. _Launch:
@@ -767,6 +1329,7 @@ Launching an exchange
A running exchange requires starting the following processes:
- ``taler-exchange-secmod-rsa`` (as special user, sharing group with the HTTPD)
+- ``taler-exchange-secmod-cs`` (as special user, sharing group with the HTTPD)
- ``taler-exchange-secmod-eddsa`` (as special user, sharing group with the HTTPD)
- ``taler-exchange-httpd`` (needs database access)
- ``taler-exchange-aggregator`` (only needs database access)
@@ -774,12 +1337,12 @@ A running exchange requires starting the following processes:
- ``taler-exchange-wirewatch`` (needs bank account read credentials and database access)
- ``taler-exchange-transfer`` (needs credentials to initiate outgoing wire transfers and database access)
-The crypto helpers must be started before the ``taler-exchange-httpd`` and
+The crypto helpers (``secmod``) must be started before the ``taler-exchange-httpd`` and
they should use the same configuration file.
For the most secure deployment, we recommend using separate users for each of
these processes to minimize information disclosures should any of them be
-compromised. The helpers do not need access to the Postgres database (and
+compromised. The helpers do not need access to the PostgreSQL database (and
thus also should not have it).
The processes that require access to the bank account need to have a
@@ -812,18 +1375,77 @@ missed.
attack surface.)
-.. _Keys-generation:
+Given proper packaging, all of the above are realized via a simple systemd
+target. This enables the various processes of an exchange service to be
+started using a simple command:
-Keys generation
----------------
+.. code-block:: shell-session
+
+ [root@exchange-online]# systemctl start taler-exchange.target
+
+.. note::
+
+ At this point, the exchange service is not yet fully operational.
+
+
+To check whether the exchange is running correctly under the advertised
+base URL, run:
+
+.. code-block:: shell-session
+
+ [root@exchange-online]# export BASE_URL=$(taler-config -s exchange -o base_url)
+ [root@exchange-online]# wget ${BASE_URL}management/keys
+
+The request might take some time to complete on slow machines, because
+a lot of key material will be generated.
+
+
+Offline Signing Setup, Key Maintenance and Tear-Down
+====================================================
+
+The exchange HTTP service must be running before you can complete the
+following offline signing procedure. Note that when an exchange is running
+without offline keys its not fully operational. To make the exchange HTTP
+service fully operational, the following steps involving the offline signing
+machine must be completed:
+
+ 1. The public keys of various online keys used by the exchange service are exported
+ via a management HTTP API.
+ 2. The offline signing system validates this request and signs it.
+ Additionally, the offline signing system signs policy messages
+ to configure the exchange's bank accounts and associated fees.
+ 3. The messages generated by the offline signing system are uploaded
+ via the management API of the exchange HTTP service.
-Once the configuration is properly set up, all the keys can be signed using
-the offline key on the offline system by the tool ``taler-exchange-offline``.
-To do this, one must first start the crypto helpers and the ``taler-exchange-httpd``
-process (the tools for wire transfers may also be started, but do not have to
-run yet).
+A typical minimal setup would look something like this:
-Next, the *future* key material should be downloaded using:
+.. code-block:: shell-session
+
+ [anybody@exchange-online]# taler-exchange-offline \
+ download > sig-request.json
+
+ [root@exchange-offline]# taler-exchange-offline \
+ sign < sig-request.json > sig-response.json
+ [root@exchange-offline]# taler-exchange-offline \
+ enable-account payto://iban/$IBAN?receiver-name=$NAME > acct-response.json
+ [root@exchange-offline]# taler-exchange-offline \
+ wire-fee now iban EUR:0 EUR:0 > fee-response.json
+ [root@exchange-offline]# taler-exchange-offline \
+ global-fee now EUR:0 EUR:0 EUR:0 4w 6y 4 > global-response.json
+
+ [anybody@exchange-online]# taler-exchange-offline upload < sig-response.json
+ [anybody@exchange-online]# taler-exchange-offline upload < acct-response.json
+ [anybody@exchange-online]# taler-exchange-offline upload < fee-response.json
+ [anybody@exchange-online]# taler-exchange-offline upload < global-response.json
+
+The following sections will discuss these steps in more depth.
+
+.. _Keys-generation:
+
+Signing the online signing keys
+-------------------------------
+
+To sign the online signing keys, first the *future* key material should be downloaded using:
.. code-block:: console
@@ -854,57 +1476,105 @@ that is able to again communicate with the exchange. On that system, run:
$ taler-exchange-offline upload < offline-sigs.json
-to provision the signatures to the exchange. At this point, the
-exchange will be able to use those keys, but wallets and merchants
-may not yet trust them! Thus, the next step is for the auditor
-to affirm that they are auditing this exchange. Details about
-this are described in :doc:`taler-auditor-manual`.
+to provision the signatures to the exchange.
+
+The ``download sign upload`` sequence in the commands above has to be done
+periodically, as it signs the various online signing keys of the exchange
+which periodically expire.
+
-The simplistic (without using offline keys for the auditor) way
-to do this would be:
+.. _exchange-account-signing:
+
+Account signing
+---------------
+
+The ``enable-account`` step is important to must be used to sign the
+``payto://`` URI in a way suitable to convince wallets that this is the
+correct address to wire funds to. Note that for each bank account, additional
+options **must** be set in the configuration file to tell the exchange how to
+access the bank account. The offline tool *only* configures the externally
+visible portions of the setup. The chapter on `bank account configuration <_exchange-bank-account-configuration>`_ has further details.
+
+taler-exchange-offline accepts additional options to configure the use of the
+account. For example, additional options can be used to add currency
+conversion or to restrict interactions to bank accounts from certain
+countries:
.. code-block:: console
- $ taler-auditor-offline download sign upload
+ $ taler-exchange-offline \
+ enable-account payto://iban/CH9300762011623852957
+ conversion-url https://conversion.example.com/
-For more information, see :doc:`manpages/taler-auditor-offline.1`.
+For details on optional ``enable-account`` arguments,
+see :doc:`manpages/taler-exchange-offline.1`.
+.. _Wire-fee-structure:
-Private key storage
--------------------
+Wire fee structure
+------------------
-Keeping the private keys the helpers create secret is paramount. If the
-private keys are lost, it is easy to provision fresh keys (with the help of
-the auditor). Thus, we recommend that the private keys of the crypto helpers
-are *not* backed up: in the rare event of a disk failure, they can be
-regenerated. However, we do recommend using RAID (1+1 or 1+1+1) for all
-disks of the system.
+.. index:: wire fee
+.. index:: fee
+For each wire method (“iban” or “x-taler-bank”) the
+exchange must know about applicable wire fees. This is also done
+using the ``taler-exchange-offline`` tool:
-.. _Database-upgrades:
+.. code-block:: console
-Database upgrades
------------------
+ $ taler-exchange-offline wire-fee 2040 iban EUR:0.05 EUR:0.10
-Currently, there is no way to upgrade the database between Taler
-versions.
+The above sets the wire fees for wire transfers involving ``iban`` accounts
+(in Euros) in the year 2040 to 5 cents (wire fee) and 10 cents (closing fee).
+The tool only supports setting fees that applies for the entire calendar year.
-The exchange database can be re-initialized using:
+We recommend provisioning an exchange with wire fees at least for the next two
+years. Note that once the fees have been set for a year, they cannot be
+changed (basically, by signing the fees the exchange makes a legally binding
+offer to the customers).
+
+.. index:: maintenance
+.. note::
+ Provisioning future wire fees, like provisioning future denomination
+ and signing keys, are key regular maintenance procedures for every
+ exchange operator. We recommend setting automated reminders for
+ this maintenance activity!
+
+
+.. _Auditor-configuration:
+
+Auditor configuration
+---------------------
+
+At this point, the exchange will be able to use those keys, but wallets and
+merchants may not yet trust them! Thus, the next step is for an auditor to
+affirm that they are auditing this exchange. Before an auditor can do this,
+the exchange service must be informed about any auditor that is expected to
+provision it with auditor signatures.
+
+This is also done using the ``taler-exchange-offline`` tool on the offline
+system. First, the auditor must be configured and provide the exchange
+operator with its public key (using ``taler-auditor-offline setup``) and the
+URL of it's REST API. The exchange operator also needs a human-readable name
+that may be shown to users to identify the auditor. For more information on
+how to setup and operate an auditor, see
+:doc:`manpages/taler-auditor-offline.1` and :doc:`taler-auditor-manual`.
+
+Given this information, the exchange operator can enable the auditor:
.. code-block:: console
- $ taler-exchange-dbinit -r
+ $ taler-exchange-offline enable-auditor $PUB_KEY $REST_URL "$AUDITOR_NAME" > auditor.json
-However, running this command will result in all data in the database
-being lost, which may result in significant financial liabilities as the
-exchange can then not detect double-spending. Hence this operation must
-not be performed in a production system.
+As before, the *auditor.json* file must then be copied from the offline system
+to a system connected to the exchange and there ``uploaded`` to the exchange using ``taler-exchange-offline upload``.
.. _Revocations:
Revocations
-^^^^^^^^^^^
+-----------
When an exchange goes out of business or detects that the private key of
a denomination key pair has been compromised, it may revoke some or all
@@ -931,24 +1601,261 @@ of ``taler-exchange-offline``.
under highly unusual (“emergency”) conditions and not in normal
operation.
-Testing a deployment
-====================
+AML Configuration
+=================
+
+The AML configuration steps are used to add or remove keys of exchange
+operator staff that are responsible for anti-money laundering (AML)
+compliance. These AML officers are shown suspicious transactions and are
+granted access to the KYC data of an exchange. They can then investigate the
+transaction and decide on freezing or permitting the transfer. They may also
+request additional KYC data from the consumer and can change the threshold
+amount above which a further AML review is triggered.
+
+AML Officer Setup
+-----------------
+
+To begin the AML setup, AML staff should launch the GNU Taler
+exchange AML SPA Web interface. (FIXME-Sebastian: how?). The
+SPA will generate a public-private key pair and store it in the
+local storage of the browser. The public key will be displayed
+and must be securely transmitted to the offline system for
+approval. Using the offline system, one can then configure
+which staff has access to the AML operations:
+
+.. code-block:: shell-session
+
+ [root@exchange-offline]# taler-exchange-offline \
+ aml-enable $PUBLIC_KEY "Legal Name" rw > aml.json
+ [root@exchange-online]# taler-exchange-offline \
+ upload < aml.json
+
+The above commands would add an AML officer with the given "Legal Name" with
+read-write (rw) access to the AML officer database. Using "ro" instead of
+"rw" would grant read-only access to the data, leaving out the ability to
+actually make AML decisions. Once AML access has been granted, the AML
+officer can use the SPA to review cases and (with "rw" access) take AML
+decisions.
+
+Access rights can be revoked at any time using:
+
+.. code-block:: shell-session
+
+ [root@exchange-offline]# taler-exchange-offline \
+ aml-disable $PUBLIC_KEY "Legal Name" > aml-off.json
+ [root@exchange-online]# taler-exchange-offline \
+ upload < aml-off.json
+
+
+AML Triggers
+------------
+
+AML decision processes are automatically triggered under certain configurable
+conditions. The primary condition that *must* be configured is the
+``AML_THRESHOLD``:
+
+.. code-block:: ini
+ :caption: /etc/taler/conf.d/exchange-business.conf
+
+ [exchange]
+ # Accounts or wallets with monthly transaction volumes above this threshold
+ # are considered suspicious and are automatically flagged for AML review
+ # and put on hold until an AML officer has reached a decision.
+ AML_THRESHOLD = "EUR:1000000"
+
+Additionally, certain KYC attributes (such as the user being a
+politically exposed person) may lead to an account being
+flagged for AML review. The specific logic is configured by
+providing the exchange with an external helper program that
+makes the decision given the KYC attributes:
+
+.. code-block:: ini
+ :caption: /etc/taler/conf.d/exchange-business.conf
+
+ [exchange]
+ # Specifies a program to run on KYC attribute data to decide
+ # whether we should immediately flag an account for AML review.
+ KYC_AML_TRIGGER = taler-exchange-kyc-aml-pep-trigger.sh
+
+The given program will be given the KYC attributes in JSON format on standard
+input, and must return 0 to continue without AML and non-zero to flag the
+account for manual review. To disable this trigger, simply leave the option to
+its default value of '[/usr/bin/]true'. To flag all new users for manual
+review, simply set the program to '[/usr/bin/]false'.
+
+AML Forms
+---------
+
+AML forms are defined by the DD 54 dynamic forms.
+The shipped implementation with of the exchange is installed in
+
+.. code-block:: shell-session
+
+ ${INSTALL_PREFIX}/share/taler/exchange/spa/forms.js
+
+
+The variable ``form`` contains the list of all form available. For
+every entry in the list the next properties are expected to be present:
+
+``label``: used in the UI as the name of the form
+
+``id``: identification name, this will be saved in the exchange database
+along with the values to correctly render the form again.
+It should simple, short and without any character outside numbers,
+letters and underscore.
+
+``version``: when editing a form, instead of just replacing fields
+it will be better to create a new form with the same id and new version.
+That way old forms in the database will used old definition of the form.
+It should be a number.
+
+``impl`` : a function that returns the design and behavior of form.
+See DD 54 dynamic forms.
+
+.. attention::
+
+ do not remove a form the list if it has been used. Otherwise you
+ won't be able to see the information save in the exchange database.
+
+To add a new one you can simply copy and paste one element, and edit it.
+
+It is much easier to download ``@gnu-taler/aml-backoffice-ui`` source
+from ``https://git.taler.net/wallet-core.git/``, compile and copy the file
+from the ``dist/prod``.
+
+
+Setup Linting
+=============
+
+The ``taler-wallet-cli`` package comes with an experimental tool that runs various
+checks on the current GNU Taler exchange deployment:
+
+.. code-block:: shell-session
+
+ [root@exchange-online]# apt install taler-wallet-cli
+ [root@exchange-online]# taler-wallet-cli deployment lint-exchange
+
+You can optionally pass the ``--debug`` option to get more verbose output, and
+``--continue`` to continue with further checks even though a previous one has
+failed.
+
+
+Testing and Troubleshooting
+===========================
We recommend testing whether an exchange deployment is functional by using the
Taler wallet command line interface. The tool can be used to withdraw and
deposit electronic cash via the exchange without having to deploy and operate a
-separate merchant backend and storefront. For more information, see
-:doc:`taler-wallet-cli-manual`.
+separate merchant backend and storefront.
+The following shell session illustrates how the wallet can be used to withdraw
+electronic cash from the exchange and subsequently spend it. For these steps,
+a merchant backend is not required, as the wallet acts as a merchant.
-.. _Diagnostics:
+.. code-block:: shell-session
-Diagnostics
-===========
+ # This will now output a payto URI that money needs to be sent to in order to allow withdrawal
+ # of taler coins.
+ $ taler-wallet-cli advanced withdraw-manually --exchange $EXCHANGE_URL --amount EUR:10.50
+
+
+Show the status of the manual withdrawal operation.
+
+.. code-block:: shell-session
+
+ $ taler-wallet-cli transactions
+
+At this point, a bank transfer to the exchange's bank account
+needs to be made with the correct subject / remittance information
+as instructed by the wallet after the first step. With the
+above configuration, it should take about 5 minutes after the
+wire transfer for the incoming transfer to be observed by the
+Nexus.
+
+Run the following command to check whether the exchange received
+an incoming bank transfer:
+
+.. code-block:: shell-session
+
+ [root@exchange-online]# taler-exchange-wire-gateway-client \
+ --section exchange-accountcredentials-1 --credit-history
+
+Once the transfer has been made, try completing the withdrawal
+using:
+
+.. code-block:: shell-session
+
+ $ taler-wallet-cli run-pending
+
+Afterwards, check the status of transactions and show the
+current wallet balance:
+
+.. code-block:: shell-session
+
+ $ taler-wallet-cli transactions
+ $ taler-wallet-cli balance
+
+
+Now, we can directly deposit coins via the exchange into a target
+account. (Usually, a payment is made via a merchant. The wallet
+provides this functionality for testing.)
+
+.. code-block:: shell-session
+
+ $ taler-wallet-cli deposit create EUR:5 \
+ payto://iban/$IBAN?receiver-name=Name
+ $ taler-wallet-cli run-pending
+
+
+Check if this transaction was successful (from the perspective
+of the wallet):
+
+.. code-block:: shell-session
+
+ $ taler-wallet-cli transactions
+
+If the transaction failed, fix any open issue(s) with the exchange and
+run the "run-pending" command.
+
+The wallet can also track if the exchange wired the money to the merchant
+account. The "deposit group id" can be found in the output of the
+transactions list.
+
+.. code-block:: shell-session
+
+ $ taler-wallet-cli deposit track $DEPOSIT_GROUP_ID
+
+You can also check using the exchange-tools whether the exchange sent
+the an outgoing transfer:
+
+.. code-block:: shell-session
+
+ [root@exchange-online]# taler-exchange-wire-gateway-client \
+ --section exchange-accountcredentials-1 --debit-history
+
+After enough time has passed, the money should arrive at the specified IBAN.
+
+For more information on the taler-wallet-cli tool, see
+:doc:`taler-wallet`.
+
+taler-config
+------------
+
+.. _Using-taler_002dconfig-exchange:
+
+.. include:: frags/using-taler-config.rst
+
+
+Private key storage
+-------------------
+
+Keeping the private keys the helpers create secret is paramount. If the
+private keys are lost, it is easy to provision fresh keys (with the help of
+the auditor). Thus, we recommend that the private keys of the crypto helpers
+are *not* backed up: in the rare event of a disk failure, they can be
+regenerated. However, we do recommend using RAID (1+1 or 1+1+1) for all
+disks of the system.
-This chapter includes various sections on specific topics that might be
-helpful to understand how the exchange operates. The information may also be
-helpful for diagnostics.
.. _Internal-audit:
@@ -993,7 +1900,363 @@ allowing administrators to purge records that are no longer required.
The database scheme used by the exchange looks as follows:
-.. image:: exchange-db.png
+.. image:: images/exchange-db.png
+
+
+.. _Database-upgrades:
+
+Database upgrades
+-----------------
+
+Before installing a new exchange version, you should probably make a backup of
+the existing database and study the release notes on migration. In general,
+the way to migrate is to stop all existing Taler exchange processes and run:
+
+.. code-block:: console
+
+ $ taler-exchange-dbinit
+
+This will migrate the existing schema to the new schema. You also may need
+to grant Taler exchange processes the rights to the new tables (see last
+step of database setup).
+
+.. note::
+
+ The **taler-exchange-dbconfig** tool can be used to automate the database
+ migration. In general, simply invoking it again should trigger the
+ migration including **taler-exchange-dbinit** and setting the permissions.
+
+
+If you do not want to keep any data from the previous installation, the
+exchange database can be fully re-initialized using:
+
+.. code-block:: console
+
+ $ taler-exchange-dbinit --reset
+
+However, running this command will result in all data in the database
+being lost, which may result in significant financial liabilities as the
+exchange can then not detect double-spending. Hence this operation must
+not be performed in a production system. You still also need to then
+grant the permissions to the other exchange processes again.
+
+
+
+.. _ExchangeTemplateCustomization:
+
+Template Customization
+======================
+
+The Exchange comes with various HTML templates that are shown to
+guide users through the KYC process. The Exchange uses `C implementation of mustache
+<https://gitlab.com/jobol/mustach>`__ as the templating engine. This section
+describes the various templates. In general, the templates must be installed
+to the ``share/taler/exchange/templates/`` directory. The file names must be of
+the form ``$NAME.$LANG.must`` where ``$NAME`` is the name of the template and
+``$LANG`` is the 2-letter language code of the template. English templates
+must exist and will be used as a fallback. If the browser (user-agent) has
+provided language preferences in the HTTP header and the respective language
+exists, the correct language will be automatically served.
+
+The following subsections give details about each of the templates. Most
+subsection titles are the ``$NAME`` of the respective template.
+
+
+Generic Errors Templates
+------------------------
+
+A number of templates are used for generic errors. These are:
+
+ * kyc-proof-already-done (KYC process already completed)
+ * kyc-bad-request (400 Bad Request)
+ * kyc-proof-endpoint-unknown (404 Not Found for KYC logic)
+ * kyc-proof-internal-error (500 Internal Server Error)
+ * kyc-proof-target-unknown (404 Not Found for KYC operation)
+
+All of these templates are instantiated using the following information:
+
+ * ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+
+ * hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+
+ * message: String; optional, extended human-readable text provided to elaborate
+ on the error, should be shown to provide additional context
+
+
+kycaid-invalid-request
+----------------------
+
+The KYCaid plugin does not support requests to the
+``/kyc-proof/`` endpoint (HTTP 400 bad request).
+
+This template is instantiated using the following information:
+
+ * ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+
+ * hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+
+ * error: String; error code from the server
+
+ * error_details: String; optional error description from the server
+
+ * error_uri: optional URI with further details about the error from the server
+
+
+
+oauth2-authentication-failure
+-----------------------------
+
+The OAuth2 server said that the request was not
+properly authenticated (HTTP 403 Forbidden).
+
+
+This template is instantiated using the following information:
+
+ * ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+
+ * hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+
+
+oauth2-authorization-failure
+----------------------------
+
+The OAuth2 server refused to return the KYC data
+because the authorization code provided was
+invalid (HTTP 403 Forbidden).
+
+This template is instantiated using the following information:
+
+ * ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+
+ * hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+
+ * error: String; error code from the server
+
+ * error_message: String; error message from the server
+
+
+oauth2-authorization-failure-malformed
+--------------------------------------
+
+The server refused the authorization, but then provided
+a malformed response (HTTP 502 Bad Gateway).
+
+This template is instantiated using the following information:
+
+ * ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+
+ * hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+
+ * debug: Bool; true if we are running in debug mode and are allowed to return HTML with potentially sensitive information
+
+ * server_response: Object; could be NULL; this includes the (malformed) OAuth2 server response, it should be shown to the use if "debug" is true
+
+
+oauth2-bad-request
+------------------
+
+The client made an invalid request (HTTP 400 Bad Request).
+
+This template is instantiated using the following information:
+
+ * ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+
+ * hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+
+ * message: String; additional error message elaborating on what was bad about the request
+
+
+oauth2-conversion-failure
+-------------------------
+
+Converting the KYC data into the exchange's internal
+format failed (HTTP 502 Bad Gateway).
+
+This template is instantiated using the following information:
+
+ * ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+
+ * hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+
+ * debug: Bool; true if we are running in debug mode and are allowed to return HTML with potentially sensitive information
+
+ * converter: String; name of the conversion command that failed which was used by the Exchange
+
+ * attributes: Object; attributes returned by the conversion command, often NULL (after all, conversion failed)
+
+ * message: error message elaborating on the conversion failure
+
+
+oauth2-provider-failure
+-----------------------
+
+We did not get an acceptable response from the OAuth2
+provider (HTTP 502 Bad Gateway).
+
+This template is instantiated using the following information:
+
+ * ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+
+ * hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+
+ * message: String; could be NULL; text elaborating on the details of the failure
+
+
+persona-exchange-unauthorized
+-----------------------------
+
+The Persona server refused our request (HTTP 403 Forbidden from Persona, returned as a HTTP 502 Bad Gateway).
+
+This template is instantiated using the following information:
+
+ * ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+
+ * hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+
+ * data: Object; data returned from Persona service, optional
+
+ * persona_http_status: Integer; HTTP status code returned by Persona
+
+
+persona-load-failure
+--------------------
+
+The Persona server refused our request (HTTP 429 Too Many Requests from Persona, returned as a HTTP 503 Service Unavailable).
+
+This template is instantiated using the following information:
+
+ * ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+
+ * hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+
+ * data: Object; data returned from Persona service, optional
+
+ * persona_http_status: Integer; HTTP status code returned by Persona
+
+
+persona-exchange-unpaid
+-----------------------
+
+The Persona server refused our request (HTTP 402 Payment REquired from Persona, returned as a HTTP 503 Service Unavailable).
+
+This template is instantiated using the following information:
+
+ * ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+
+ * hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+
+ * data: Object; data returned from Persona service, optional
+
+ * persona_http_status: Integer; HTTP status code returned by Persona
+
+
+
+persona-logic-failure
+---------------------
+
+The Persona server refused our request (HTTP 400, 403, 409, 422 from Persona, returned as a HTTP 502 Bad Gateway).
+
+This template is instantiated using the following information:
+
+ * ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+
+ * hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+
+ * data: Object; data returned from Persona service, optional
+
+ * persona_http_status: Integer; HTTP status code returned by Persona
+
+
+persona-invalid-response
+------------------------
+
+The Persona server refused our request in an
+unexpected way; returned as a HTTP 502 Bad Gateway.
+
+This template is instantiated using the following information:
+
+ * ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+
+ * hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+
+ * debug: Bool; true if we are running in debug mode and are allowed to return HTML with potentially sensitive information
+
+ * server_response: Object; could be NULL; this includes the (malformed) OAuth2 server response, it should be shown to the use if "debug" is true
+
+
+persona-network-timeout
+-----------------------
+
+The Persona server refused our request (HTTP 408 from Persona, returned as a HTTP 504 Gateway Timeout).
+
+This template is instantiated using the following information:
+
+ * ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+
+ * hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+
+ * data: Object; data returned from Persona service, optional
+
+ * persona_http_status: Integer; HTTP status code returned by Persona
+
+
+persona-kyc-failed
+------------------
+
+The Persona server indicated a problem with the KYC process, saying it was not completed.
+
+This template is instantiated using the following information:
+
+ * persona_inquiry_id: String; internal ID of the inquiry within Persona, useful for further diagnostics by staff
+
+ * data: Object; could be NULL; this includes the server response, it contains extensive diagnostics, see Persona documentation on their ``/api/v1/inquiries/$ID``.
+
+ * persona_http_status: Integer; HTTP status code returned by Persona
+
+persona-provider-failure
+------------------------
+
+The Persona server refused our request (HTTP 500 from Persona, returned as a HTTP 502 Bad Gateway).
+
+This template is instantiated using the following information:
+
+ * ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+
+ * hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+
+ * data: Object; data returned from Persona service, optional
+
+ * persona_http_status: Integer; HTTP status code returned by Persona
.. _ExchangeBenchmarking:
@@ -1001,61 +2264,164 @@ The database scheme used by the exchange looks as follows:
Benchmarking
============
-This chapter describes how to run the Taler exchange benchmark. The benchmark
-can be used to measure the performance of the exchange by running a (possibly
-large) number of simulated clients against one Taler deployment with a bank,
-exchange and auditor. For the bank, both a "fakebank" (``-f``) and a
-"Pythonbank" deployment are currently supported. The
-``taler-exchange-benchmark`` program can launch all required services and
-clients, or only launch the parallel clients (``-m``), for example for
-distributed testing over a network.
-
-For each *parallel* (``-p``) client, a number of *reserves* (``-r``) is first established by
-**transferring** money from a "user" account (42) to the Exchange's account
-with the respective reserve public key as wire subject. Next, the
-client will **withdraw** a *number of coins* (``-n``) from the reserve and
-**deposit** them. Additionally, a *fraction* (``-R``) of the dirty coins will then be
-subject to **refreshing**. For some deposits, the auditor will receive
-**deposit confirmations**.
-
-Operations that are not covered today include closing reserves, refunds and
-recoups.
-
-The existing ``benchmark.conf`` file in ``src/benchmark/`` can be used as a
-starting point for a configuration to run the benchmark. The existing
-configuration file only requires that the ``talercheck`` database already
-exists and will launch all required services locally as needed.
-
-You can run a first simple benchmark using:
+This chapter describes how to run various benchmarks against a Taler exchange.
+These benchmark can be used to measure the performance of the exchange by
+running a (possibly large) number of simulated clients against one Taler
+deployment with a bank, exchange and (optionally) auditor.
+
+Real benchmarks that are intended to demonstrate the scalability of GNU Taler
+should not use the tools presented in this section: they may be suitable for
+microbenchmarking and tuning, but the setup is inherently not optimzied for
+performance or realism, both for the load generation and the server side.
+Thus, we do not recommend using these performance numbers to assess the
+scalability of GNU Taler. That said, the tools can be useful to help identify
+performance issues.
+
+The ``taler-unified-setup.sh`` script can be used to launch all required
+services and clients. However, the resulting deployment is simplistic
+(everything on the local machine, one single-threaded process per service
+type) and not optimized for performance at all. However, this can still be
+useful to assess the performance impact of changes
+to the code or configuration.
+
+The various configuration files used in the code snippets in this section can
+be found in the ``src/benchmark/`` directory of the exchange. These are
+generally intended as starting points. Note that the configuration files
+ending in ``.edited`` are created by ``taler-unified-setup.sh`` and contain
+some options that are determined at runtime by the setup logic provided by
+``taler-unified-setup.sh``.
+
+
+.. _Benchmark-choose-bank:
+
+Choosing a bank
+---------------
-.. note::
- FIXME-TTN/CG: these instructions are incomplete and untested for the
- current iteration of the code...
+For the bank, both a fakebank (``-f``) and libeufin-based (``-ns``)
+bank deployment are currently supported by all benchmark tools and
+configuration templates.
+
+Fakebank is an ultra-fast in-memory implementation of the Taler bank API. It
+is suitable when the goal is to benchmark the core GNU Taler payment system
+and to ignore the real-time gross settlement (RTGS) system typically provided
+by an existing bank. When using the fakebank, ``taler-unified-setup.sh`` must
+be started with the ``-f`` option and be told to use the right exchange bank
+account from the configuration files via ``-u exchange-account-1``.
+
+.. code-block:: console
+
+ $ dropdb talercheck; createdb talercheck
+ $ taler-unified-setup.sh -emwt -c $CONF -f -u exchange-account-1
+
+
+libeufin is GNU Taler's adapter to the core banking system using the EBICS
+banking protocol standard. It uses a Postgres database to persist data and is
+thus much slower than fakebank. If your GNU Taler deployment uses libeufin in
+production, it likely makes sense to benchmark with libeufin. When using the
+fakebank, ``taler-unified-setup.sh`` must be started with the ``-ns`` options
+(starting libeufin-nexus and libeufin-bank) and be told to use the right
+exchange bank account from the configuration files via ``-u
+exchange-account-2``. Note that ``taler-unified-setup.sh`` currently cannot
+reset a libeufin database, and also will not run if the database is already
+initialized. Thus, you must re-create the database every time before
+running the command:
+
+.. code-block:: console
+
+ $ dropdb talercheck; createdb talercheck
+ $ taler-unified-setup.sh -emwt -c $CONF -ns -u exchange-account-2
+
+
+taler-bank-benchmark
+--------------------
+
+This is the simplest benchmarking tool, simulating only the bank
+interaction.
+
+.. code-block:: console
+
+ $ CONF="benchmark-cs.conf"
+ $ # or with libeufin
+ $ dropdb talercheck; createdb talercheck
+ $ taler-unified-setup.sh -emwt -c "$CONF" -f -u exchange-account-1
+ $ # Once <<READY>>, in another shell (remember to set $CONF):
+ $ time taler-bank-benchmark -c "$CONF" -r 40 -p 4 -P4 -u exchange-account-1 -f
+ $ # or with libeufin
+ $ dropdb talercheck; createdb talercheck
+ $ taler-unified-setup.sh -emwt -c "$CONF" -ns -u exchange-account-2
+ $ # Once <<READY>>, in another shell (remember to set $CONF):
+ $ time taler-bank-benchmark -c "$CONF" -r 40 -p 1 -P1 -u exchange-account-2
+
+For each *parallel* (``-p``) client, a number of *reserves* (``-r``) is first
+established by **transferring** money from a "user" account (42) to the
+Exchange's account with the respective reserve public key as wire subject.
+Processing is then handled by *parallel* (``-P``) service workers.
+
+
+taler-exchange-benchmark
+------------------------
+
+This is the benchmarking tool simulates a number of clients withdrawing,
+depositing and refreshing coins. Operations that are not covered by the
+``taler-exchange-benchmark`` tool today include closing reserves, refunds,
+recoups and P2P payments.
.. code-block:: console
- $ createdb talercheck # if it does not yet exist
- $ taler-exchange-dbinit -c benchmark.conf
- $ taler-exchange-httpd -c benchmark.conf &
- $ HTTPD_PID=$!
- $ taler-exchange-offline -c benchmark.conf \
- download sign \
- enable-account FIXME-DETAILS-MISING-HERE \
- wire-fee FIXME-DETAILS-MISING-HERE \
- upload
- $ kill -TERM $HTTPD_PID
- $ taler-exchange-benchmark -c benchmark.conf -p 4 -r 1 -n 10
-
-This will run 4 parallel clients withdrawing 10 coins from 1 reserve and then
-depositing those coins. The default refresh probability is 10 percent. Note
-that the tiny run should only take a few seconds, most of it will be spent in
-the setup of the original key material. For meaningful runs, all three values
-should likely be increased.
+ $ CONF="benchmark-cs.conf" # -rsa also makes sense
+ $ # With fakebank
+ $ dropdb talercheck; createdb talercheck
+ $ taler-unified-setup.sh -aemwt -c "$CONF" -f -u exchange-account-1
+ $ # Once <<READY>>, in another shell (remember to set $CONF):
+ $ taler-exchange-benchmark -c "$CONF".edited -u exchange-account-1 -n 1 -p1 -r 5 -f
+ $ #
+ $ # With libeufin
+ $ dropdb talercheck; createdb talercheck
+ $ taler-unified-setup.sh -aemwt -c "$CONF" -ns -u exchange-account-2
+ $ # Once <<READY>>, in another shell (remember to set $CONF):
+ $ taler-exchange-benchmark -c "$CONF".edited -u exchange-account-2 -L WARNING -n 1 -p1 -r 5
+
+For each *parallel* (``-p``) client, a number of *reserves* (``-r``) is first
+established by **transferring** money from a "user" account (42) to the
+Exchange's account with the respective reserve public key as wire subject.
+Next, the client will **withdraw** a *number of coins* (``-n``) from the
+reserve and **deposit** them. Additionally, a *fraction* (``-R``) of the dirty
+coins will then be subject to **refreshing**. For some deposits, the auditor
+will receive **deposit confirmations**.
The output of ``taler-exchange-benchmark`` will include for each parallel
client the total time spent in each of the major operations, possible
repetitions (i.e. if the operation failed the first time), total execution
time (operating system and user space) and other details.
-Naturally, additional instrumentation (including using features of the
-Postgres database itself) may help discover performance issues.
+
+taler-aggregator-benchmark
+--------------------------
+
+This is another simple benchmark tool that merely prepares an exchange
+database to run a stand-alone benchmark of the ``taler-exchange-aggregator``
+tool. After preparing a database and running the tool, you can then
+run one or more ``taler-exchange-aggregator`` processes and measure how
+quickly they perform the aggregation work.
+
+.. code-block:: console
+
+ $ CONF=benchmark-rsa.conf
+ $ taler-exchange-dbinit -c "$CONF" --reset
+ $ ./taler-aggregator-benchmark -c "$CONF" -m 500 -r 10 -d 100
+ $ time taler-exchange-aggregator -c "$CONF" --test
+
+This above commands will first create 100 deposits with 10 refunds into each
+of 500 merchant accounts using randomized time stamps. Afterwards, it will
+time a single aggregator process in ``--test`` mode (asking it to terminate
+as soon as there is no more pending work).
+
+
+FIXMEs
+======
+
+* We should have some summary with the inventory of services that should be
+ running. Systemd by default doesn't show this nicely. Maybe suggest running
+ "systemd list-dependencies taler-exchange.target"?
+* What happens when the TWG doesn't like one particular outgoing transaction?
+ How to recover from that as a sysadmin when it happens in practice?
diff --git a/taler-exchange-setup-guide.rst b/taler-exchange-setup-guide.rst
deleted file mode 100644
index d56a51bd..00000000
--- a/taler-exchange-setup-guide.rst
+++ /dev/null
@@ -1,987 +0,0 @@
-..
- This file is part of GNU Taler.
-
- Copyright (C) 2021 Taler Systems SA
-
- GNU Taler 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.
-
- GNU 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 Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-
- @author Florian Dold
-
-GNU Taler Exchange Setup Guide
-##############################
-
-This setup guide walks a system administrator through all steps required to
-install an exchange and check that it is functional. For more background,
-please read the :doc:`Operator Manual <taler-exchange-manual>`.
-
-
-System Requirements
-===================
-
-This guide assumes that you are running Ubuntu 20.04 (Focal Fossa).
-
-We recommend the setup of offline signing keys to be done on a second machine that
-does not have Internet access.
-
-In this guide's shell-session fragments, the command prompt shows two pieces
-of information:
-
-* Who is performing the command
- (``$user`` vs ``root``, and ending character ``$`` vs ``#``).
-* Host where the command is supposed to be executed
- (``exchange-offline`` vs ``exchange-online``).
- It is possible to do the entire setup on one machine,
- but we do not recommend this for security reasons.
-
-
-Before you start
-================
-
-To deploy this with a real bank, you need:
-
-* IBAN of the bank account to use
-* BIC of the bank
-* EBICS host, user and partner IDs
-
-Information to write down during the installation:
-
-* LibEuFin Nexus superuser password
-* Taler facade base URL
-* exchange Nexus username and password
-
-
-
-Installation
-============
-
-We assume that the system is a minimal installation of Ubuntu 20.04 LTS.
-Ideally, you should have two hosts, ``exchange-online`` and
-``exchange-offline``. It is also possible to run the HTTPS nginx server or
-the PostgreSQL database on yet another host, but in these instructions we will
-assume that only two hosts are used. Alas, the instructions will also work if
-you run everything on one system, but then you have the security drawback of
-not keeping the high-security private keys disconnected from the Internet.
-
-To install the exchange, first make sure that your system is up-to-date
-and that the ``gnupg`` package has been installed.
-
-.. code-block:: shell-session
-
- [root@exchange-online]# apt-get update
- [root@exchange-online]# apt-get upgrade
-
-Next, add the ``focal-fossa`` apt repository provided by Taler Systems S.A. to
-your package sources:
-
-.. code-block:: shell-session
-
- [root@exchange-online]# cat > /etc/apt/sources.list.d/taler.list <<EOF
- deb https://deb.taler.net/apt/ubuntu focal-fossa main
- EOF
- [root@exchange-online]# dpkg --remove-architecture i386
-
-The second command is optional. It tells ``apt-get update`` to not
-bother with the ``i386`` architecture (thus avoiding a warning, later).
-If you use this, make sure you do not use any 32-bit applications.
-
-Before installing Taler packages, you need to add the Taler Systems S.A. package
-signing key to your list of trusted keys and update the package index:
-
-.. code-block:: shell-session
-
- [root@exchange-online]# wget -O - https://taler.net/taler-systems.gpg.key | apt-key add -
- [root@exchange-online]# apt-get update
-
-Finally, the required packages can be installed:
-
-.. code-block:: shell-session
-
- [root@exchange-online]# apt-get install -y nginx postgresql
- [root@exchange-online]# apt-get install -y taler-exchange taler-exchange-offline
- [root@exchange-online]# apt-get install -y taler-wallet-cli
-
-By default, all installed services will be disabled. You need to enable
-and start them later.
-
-While ``taler-merchant`` and ``taler-wallet`` are not required to operate an
-exchange, they are useful for testing. When asked about using dbconfig to configure
-the merchant's database, select ``yes``.
-
-
-Configuration Basics
-====================
-
-The configuration for all Taler components uses a single configuration file
-as entry point: ``/etc/taler/taler.conf``.
-
-System defaults are automatically loaded from files in
-``/usr/share/taler/config.d``. These default files should never be modified.
-
-The default configuration ``taler.conf`` configuration file also includes all
-configuration files in ``/etc/taler/conf.d``. The settings from files in
-``conf.d`` are only relevant to particular components of Taler, while
-``taler.conf`` contains settings that affect all components.
-
-
-The directory ``/etc/taler/secrets`` contains configuration file snippets with
-values that should only be readable to certain users. They are included with the ``@inline-secret@``
-directive and should end with ``.secret.conf``.
-
-To view the entire configuration annotated with the source of each configuration option, you
-can use the ``taler-config`` helper:
-
-
-.. code-block:: shell-session
-
- [root@exchange-online]# taler-config --diagnostics
- < ... annotated, full configuration ... >
-
-.. warning::
-
- While ``taler-config`` also supports rewriting configuration files, we strongly
- recommend to edit configuration files manually, as ``taler-config`` does not
- preserve comments and, by default, rewrites ``/etc/taler/taler.conf``.
-
-
-Services, users, groups and file system hierarchy
-=================================================
-
-The *taler-exchange-httpd* package will create several system users
-to compartmentalize different parts of the system:
-
-* ``taler-exchange-httpd``: runs the HTTP daemon with the core business logic.
-* ``taler-exchange-secmod-rsa``: manages the RSA private online signing keys.
-* ``taler-exchange-secmod-eddsa``: manages the EdDSA private online signing keys.
-* ``taler-exchange-closer``: closes idle reserves by triggering wire transfers that refund the originator.
-* ``taler-exchange-aggregator``: aggregates deposits into larger wire transfer requests.
-* ``taler-exchange-wire``: performs wire transfers with the bank (via LibEuFin/Nexus).
-* ``postgres``: runs the Postgres database (from *postgres* package).
-* ``www-data``: runs the frontend HTTPS service with the TLS keys (from *nginx* package).
-
-.. note::
-
- The *taler-merchant-httpd* package additionally creates a taler-merchant-httpd user
- to runs the HTTP daemon with the merchant business logic.
-
-
-The exchange setup uses the following system groups:
-
-* ``taler-exchange-db``: group for all Taler users with direct database access, specifically taler-exchange-httpd, taler-exchange-wire, taler-exchange-closer and taler-exchange-aggregator.
-* ``taler-exchange-secmod``: group for processes with access to online signing keys; this group must have three users: taler-exchange-secmod-rsa, taler-exchange-secmod-eddsa and taler-exchange-httpd.
-* ``taler-exchange-offline``: group for the access to the offline private key (only used on the offline host and not used on the online system).
-
-
-
-The package will deploy systemd service files in
-``/usr/lib/systemd/system/`` for the various components:
-
-* ``taler-exchange-aggregator.service``: service that schedules wire transfers
- which combine multiple deposits to the same merchant.
-* ``taler-exchange-closer.service``: service that watches for reserves that have been abandoned and schedules wire transfers to send the money back to the originator.
-* ``taler-exchange-httpd.service``: main Taler exchange logic with the public REST API.
-* ``taler-exchange-httpd.socket``: systemd socket activation for the Taler exchange HTTP daemon.
-* ``taler-exchange-secmod-eddsa.service``: software security module for making EdDSA signatures.
-* ``taler-exchange-secmod-rsa.service``: software security module for making RSA signatures.
-* ``taler-exchange-transfer.service``: service that triggers outgoing wire transfers (pays merchants).
-* ``taler-exchange-wirewatch.service``: service that watches for incoming wire transfers (first step of withdraw).
-* ``taler-exchange.target``: Main target for the Taler exchange to be operational.
-
-
-The deployment creates the following key locations in the system:
-
-* ``/etc/taler/``: configuration files.
-* ``/run/taler/``: contains the UNIX domain sockets for inter-process communication (IPC).
-* ``/var/lib/taler/``: serves as the $HOME for all Taler users and contains sub-directories
- with the private keys; which keys are stored here depends on the host:
-
- * online system: exchange-secmod-eddsa and exchange-secmod-rsa keys.
- * offline system: exchange-offline keys.
-
-
-Setup Linting
-=============
-
-The ``taler-wallet-cli`` package comes with a experimental tool that runs various
-checks on the current GNU Taler exchange deployment:
-
-.. code-block:: shell-session
-
- [root@exchange-online]# taler-wallet-cli deployment lint-exchange
-
-You can optionally pass the ``--debug`` option to get more verbose output, and
-``--continue`` to continue with further checks even though a previous one has
-failed.
-
-Basic Setup: Currency and Denominations
-=======================================
-
-A Taler exchange only supports a single currency. The currency
-and the smallest currency unit supported by the bank system
-must be specified in ``/etc/taler/taler.conf``.
-
-.. code-block:: ini
- :caption: /etc/taler/taler.conf
-
- [taler]
- CURRENCY = EUR
- CURRENCY_ROUND_UNIT = EUR:0.01
-
- # ... rest of file ...
-
-.. warning::
-
- When editing ``/etc/taler/taler.conf``, take care to not accidentally remove
- the @inline-matching@ directive to include the configuration files in ``conf.d``.
-
-Next, the electronic cash denominations that the exchange offers must be
-specified. The ``taler-wallet-cli`` has a helper command that generates a
-reasonable denomination structure.
-
-.. code-block:: shell-session
-
- taler-wallet-cli deployment gen-coin-config --min-amount EUR:0.01 --max-amount EUR:100 > /etc/taler/conf.d/exchange-coins.conf
-
-You can manually review and edit the generated configuration file. The main
-change that is possibly required is updating the various fees.
-
-
-Wire Gateway Setup
-==================
-
-The Taler Wire Gateway is an API that connects the Taler exchange to
-the underlying core banking system.
-
-LibEuFin is an implementation of the Wire Gateway API for the EBICS protocol.
-This section will walk through (1) installing and configuring LibEuFin and
-(2) connecting the Taler Exchange to LibEuFin.
-
-.. note::
-
- If you do not have a bank account with EBICS but want to test these instructions,
- you can use the EBICS sandbox as described in the
- :doc:`LibEuFin Tutorial <libeufin/nexus-tutorial>`.
-
-
-Installation and Basic Configuration
-------------------------------------
-
-First, install the ``libeufin`` package. This can be done on the ``exchange-online``
-machine or a different one.
-
-.. code-block:: shell-session
-
- [root@exchange-online]# apt-get install -y libeufin
-
-The main component of LibEuFin is called the Nexus. It implements a Web
-service that provides a JSON abstraction layer to access bank accounts.
-
-The Nexus currently uses an sqlite3 database as storage by default.
-We currently recommend to stick with this default. In future
-versions, there will be a migration path to a PostgreSQL database.
-
-The HTTP port and database connection string can be edited in the configuration:
-
-.. code-block:: ini
- :caption: /etc/libeufin/nexus.env
-
- LIBEUFIN_NEXUS_PORT=5017
- LIBEUFIN_NEXUS_DB_CONNECTION=jdbc:sqlite:/var/lib/libeufin/nexus/nexus-db.sqlite3
-
-After configuring the database, you can start the service.
-The database is initialized automatically.
-
-
-.. code-block:: shell-session
-
- [root@exchange-online]# systemctl enable libeufin-nexus
- [root@exchange-online]# systemctl start libeufin-nexus
-
-You can now create a superuser account. The command to
-create the superuser needs direct database access, thus
-the configuration file is sourced first, and the relevant
-environment variable is exported.
-
-.. code-block:: console
-
- [root@exchange-online]# source /etc/libeufin/nexus.env
- [root@exchange-online]# export LIBEUFIN_NEXUS_DB_CONNECTION
- [root@exchange-online]# NEXUS_ADMIN_PW=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 13)
- [root@exchange-online]# libeufin-nexus superuser admin --password $NEXUS_ADMIN_PW
-
-If you omit ``--password $NEXUS_ADMIN_PW``, you will interactively be asked for a password.
-For simplicity, a superuser can as well act as a normal user, but an API
-to create less privileged users is offered.
-
-.. note::
-
- User and permissions management in LibEuFin is still under development.
- In particular, permissions for non-superusers are very limited at the moment.
-
-
-Connecting Nexus with an EBICS account
---------------------------------------
-
-The command line interface of the LibEuFin Nexus needs the following three
-values to be defined in the environment: ``LIBEUFIN_NEXUS_URL``,
-``LIBEUFIN_NEXUS_USERNAME``, and ``LIBEUFIN_NEXUS_PASSWORD``. In this example,
-``LIBEUFIN_NEXUS_USERNAME`` should be set to ``admin``, and
-``LIBEUFIN_NEXUS_PASSWORD`` to the value hold in ``NEXUS_ADMIN_PW`` from the
-previous step (the ``libeufin-nexus superuser`` command). The
-``LIBEUFIN_NEXUS_URL`` could be given as ``http://localhost:5017/``.
-
-Next, we create a EBICS *bank connection* that Nexus can use to communicate with the bank.
-
-.. code-block:: console
-
- [root@exchange-online]# libeufin-cli \
- connections \
- new-ebics-connection \
- --ebics-url $EBICS_BASE_URL \
- --host-id $EBICS_HOST_ID \
- --partner-id $EBICS_PARTNER_ID \
- --ebics-user-id $EBICS_USER_ID \
- $CONNECTION_NAME
-
-If this step executes correctly, Nexus will have created all the cryptographic
-material that is needed on the client side; in this EBICS example, it created
-the signature and identification keys. It is therefore advisable to *make
-a backup copy* of such keys.
-
-.. code-block:: console
-
- [root@exchange-online]# libeufin-cli \
- connections \
- export-backup \
- --passphrase $SECRET \
- --output-file $BACKUP_FILE \
- $CONNECTION_NAME
-
-At this point, Nexus needs to both communicate its keys to the bank, and
-download the bank's keys. This syncronization happens through the INI, HIA, and
-finally, HPB message types.
-
-After the electronic synchronization, the subscriber must confirm their keys
-by sending a physical mail to the bank. The following command helps generating
-such letter:
-
-.. code-block:: console
-
- [root@exchange-online]# libeufin-cli connections get-key-letter $CONNECTION_NAME out.pdf
-
-.. code-block:: console
-
- [root@exchange-online]# libeufin-cli \
- connections \
- connect \
- $CONNECTION_NAME
-
-..
- FIXME: Maybe is not 100% clear that 'connecting' means exchanging keys
- wiht the bank?
-
-Once the connection is synchronized, Nexus needs to import locally the data
-corresponding to the bank accounts offered by the bank connection just made.
-The command below downloads the list of the bank accounts offered by ``$CONNECTION_NAME``.
-
-.. code-block:: console
-
- [root@exchange-online]# libeufin-cli \
- connections \
- download-bank-accounts \
- $CONNECTION_NAME
-
-It is now possible to list the accounts offered by the connection.
-
-.. code-block:: console
-
- [root@exchange-online]# libeufin-cli \
- connections \
- list-offered-bank-accounts \
- $CONNECTION_NAME
-
-.. note::
-
- The ``nexusBankAccountId`` field should at this step be ``null``,
- as we have not yet imported the bank account and thus the account
- does not yet have a local name.
-
-Nexus now needs an explicit import of the accounts it should manage. This
-step is needed to let the user pick a custom name for such accounts.
-
-.. code-block:: console
-
- [root@exchange-online]# libeufin-cli \
- connections \
- import-bank-account \
- --offered-account-id testacct01 \
- --nexus-bank-account-id $LOCAL_ACCOUNT_NAME \
- $CONNECTION_NAME
-
-Once a Nexus user imported a bank account (``$LOCAL_ACCOUNT_NAME``)
-under a certain connection (``$CONNECTION_NAME``), it is possible
-to accomplish the usual operations for any bank account: asking for the
-list of transactions, and making a payment.
-
-Testing: Requesting the transaction history
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The LibEuFin Nexus keeps a local copy of the bank account's transaction
-history. Before querying transactions locally, it is necessary
-to request transactions for the bank account via the bank connection.
-
-This command asks Nexus to download the latest transaction reports/statements
-through the bank connection:
-
-.. code-block:: console
-
- [root@exchange-online]# libeufin-cli accounts fetch-transactions $LOCAL_ACCOUNT_NAME
-
-.. note::
-
- By default, the latest available transactions are fetched. It is also
- possible to specify a custom date range (or even all available transactions)
- and the type of transactions to fetch (inter-day statements or intra-day
- reports).
-
-..
- FIXME: Possibly the date range filter is still missing, see #6243.
-
-Once Nexus has stored all the information in the database, the
-client can ask to actually see the transactions:
-
-.. code-block:: console
-
- [root@exchange-online]# libeufin-cli accounts transactions $LOCAL_ACCOUNT_NAME
-
-Testing: Making payments
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-Payments pass through two phases: preparation and submission. The preparation
-phase assigns the payment initiation a unique ID, which prevents accidental
-double submissions of payments in case of network failures or other
-disruptions.
-
-
-The following command prepares a payment:
-
-.. code-block:: console
-
- [root@exchange-online]# libeufin-cli accounts prepare-payment \
- --creditor-iban=$IBAN_TO_SEND_MONEY_TO \
- --creditor-bic=$BIC_TO_SEND_MONEY_TO \
- --creditor-name=$CREDITOR_NAME \
- --payment-amount=$AMOUNT \
- --payment-subject=$SUBJECT \
- $LOCAL_ACCOUNT_NAME
-
-Note: the ``$AMOUNT`` value needs the format ``X.Y:CURRENCY``; for example
-``EUR:10``, or ``EUR:1.01``.
-
-The previous command should return a value (``$UUID``) that uniquely
-identifies the prepared payment in the Nexus system. That is needed
-in the next step, to **send the payment instructions to the bank**:
-
-.. code-block:: console
-
- [root@exchange-online]# libeufin-cli accounts submit-payment \
- --payment-uuid $UUID \
- $LOCAL_ACCOUNT_NAME
-
-Automatic scheduling
-~~~~~~~~~~~~~~~~~~~~
-
-With an EBICS bank connection, the LibEuFin Nexus needs to regularly query for
-new transactions and (re-)submit prepared payments.
-
-It is possible to schedule these tasks via an external task scheduler such as
-cron(8). However, the nexus also has an internal task scheduling mechanism for
-accounts.
-
-
-The following three commands create a schedule for submitting payments hourly,
-fetching transactions (intra-day reports) every 5 minutes, and (inter-day statements)
-once at 11pm every day:
-
-.. code-block:: console
-
- [root@exchange-online]# libeufin-cli accounts task-schedule $LOCAL_ACCOUNT_NAME \
- --task-type="submit" \
- --task-name='submit-payments-hourly' \
- --task-cronspec='0 0 *'
-
- [root@exchange-online]# libeufin-cli accounts task-schedule $LOCAL_ACCOUNT_NAME \
- --task-type="fetch" \
- --task-name='fetch-5min' \
- --task-cronspec='0 */5 *' \
- --task-param-level=report \
- --task-param-range-type=latest
-
- [root@exchange-online]# libeufin-cli accounts task-schedule $LOCAL_ACCOUNT_NAME \
- --task-type="fetch" \
- --task-name='fetch-daily' \
- --task-cronspec='0 0 23' \
- --task-param-level=statement \
- --task-param-range-type=latest
-
-The cronspec has the following format, which is slightly non-standard due to
-the ``SECONDS`` field
-
-.. code-block:: none
-
- SECONDS MINUTES HOURS DAY-OF-MONTH[optional] MONTH[optional] DAY-OF-WEEK[optional]
-
-
-Creating a Taler facade
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Facades are additional abstraction layers that can serve
-specific purposes. For example, one application might need
-a filtered version of the transaction history, or it might
-want to refuse payments that do not conform to certain rules.
-
-At this moment, only the *Taler facade type* is implemented
-in the Nexus, and the command below instantiates one under a
-existing bank account / connection pair. You can freely
-assign an identifier for the ``$FACADE_NAME`` below:
-
-.. code-block:: console
-
- [root@exchange-online]# libeufin-cli facades new-taler-wire-gateway-facade \
- --currency EUR \
- --facade-name $FACADE_NAME \
- $CONNECTION_NAME \
- $LOCAL_ACCOUNT_NAME
-
-At this point, the additional :doc:`taler-wire-gateway API <core/api-wire>`
-becomes offered by the Nexus. The purpose is to let a Taler exchange rely on
-Nexus to manage its bank account.
-
-The base URL of the facade that can be used by the Taler exchange
-as the Taler Wire Gateway base URL can be seen by listing the facades:
-
-.. code-block:: console
-
- [root@exchange-online]# libeufin-cli facades list
-
-Managing Permissions and Users
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This guide has so far assumed that a superuser is accessing the LibEuFin Nexus.
-However, it is advisable that the Nexus is accessed with users that only have a
-minimal set of permissions.
-
-The Nexus currently only has support for giving non-superusers access to Taler
-wire gateway facades.
-
-To create a new user, use the ``users`` subcommand of the CLI:
-
-.. code-block:: console
-
- [root@exchange-online]# libeufin-cli users list
- # [ ... shows available users ... ]
-
- [root@exchange-online]# libeufin-cli users create $USERNAME
- # [ ... will prompt for password ... ]
-
-Permissions are managed with the ``permissions`` subcommand.
-The following commands grant permissions to view the transaction history
-and create payment initiations with a Taler wire gateway facade:
-
-
-.. code-block:: console
-
- [root@exchange-online]# libeufin-cli permissions grant \
- user $USERNAME \
- facade $FACADENAME \
- facade.talerwiregateway.history
-
- [root@exchange-online]# libeufin-cli permissions grant \
- user $USERNAME \
- facade $FACADENAME \
- facade.talerwiregateway.transfer
-
-..
- FIXME: The two commands above output a empty JSON object
- when successful. Possibly, we should suppress that (just like
- the other commands do).
-
-The list of all granted permissions can be reviewed:
-
-.. code-block:: console
-
- [root@exchange-online]# libeufin-cli permissions list
-
-
-Exchange Wire Configuration
----------------------------
-
-The exchange must be configured with the right settings to
-access the Taler Wire Gateway. An exchange can be configured
-to use multiple bank accounts by using multiple Wire Gateways.
-Typically only one Wire Gateway is used.
-
-A Taler Wire Gateway is configured in a configuration section that follows the
-pattern ``exchange-account-$id``, where ``$id`` is an internal identifier for
-the bank account accessed by the exchange. The basic information for an account should
-be put in ``/etc/taler/conf.d/exchange-business.conf``.
-The secret credentials to access the Taler Wire Gateway API should
-be put into a corresponding ``exchange-accountcredentials-$id`` section
-in ``/etc/taler/secrets/exchange-accountcredentials.conf``.
-The latter file
-should already be only readable for the ``taler-exchange-wire`` user. Other
-exchange processes should not have access to this information.
-
-.. code-block:: ini
- :caption: /etc/taler/conf.d/exchange-business.conf
-
- [exchange-account-1]
- enable_credit = yes
- enable_debit = yes
-
- # Account identifier in the form of an RFC-8905 payto:// URI.
- # For SEPA, looks like payto://sepa/$IBAN?receiver-name=$NAME
- # Make sure to URL-encode spaces in $NAME!
- payto_uri =
-
- @inline-secret@ exchange-accountcredentials-1 ../secrets/exchange-accountcredentials.secret.conf
-
-
-.. code-block:: ini
- :caption: /etc/taler/secrets/exchange-accountcredentials.secret.conf
-
- [exchange-accountcredentials-1]
-
- # LibEuFin expects basic auth.
- wire_gateway_auth_method = basic
-
- # Username and password set in LibEuFin.
- username = ...
- password = ...
-
- # Base URL of the wire gateway set up with LibEuFin.
- wire_gateway_url = ...
-
-
-The Wire Gateway configuration can be tested with the following command:
-
-.. code-block:: shell-session
-
- [root@exchange-online]# taler-exchange-wire-gateway-client \
- --section exchange-accountcredentials-1 --debit-history
- [root@exchange-online]# taler-exchange-wire-gateway-client \
- --section exchange-accountcredentials-1 --credit-history
-
-
-
-Exchange Database Setup
-=======================
-
-The access credentials for the exchange's database are configured in
-``/etc/taler/secrets/exchange-db.secret.conf``. Currently, only PostgreSQL is
-supported as a database backend.
-
-The following users must have access to the exchange database:
-
-* taler-exchange-httpd
-* taler-exchange-wire
-* taler-exchange-aggregator
-* taler-exchange-closer
-
-These users are all in the taler-exchange-db group, and the
-``exchange-db.secret.conf`` should already be only readable by users in
-this group.
-
-To create a database for the Taler exchange on the local system, run:
-
-.. code-block:: shell-session
-
- [root@exchange-online]# su - postgres
- [postgres@exchange-online]# createuser taler-exchange-httpd
- [postgres@exchange-online]# createuser taler-exchange-wire
- [postgres@exchange-online]# createuser taler-exchange-aggregator
- [postgres@exchange-online]# createuser taler-exchange-closer
- [postgres@exchange-online]# createdb -O taler-exchange-httpd taler-exchange
- [postgres@exchange-online]# exit
-
-This will create a ``taler-exchange`` database owned by the
-``taler-exchange-httpd`` user. We will use that user later to perform
-database maintenance operations.
-
-
-Assuming the above database setup, the database credentials to configure
-in the configuration file would simply be:
-
-.. code-block:: ini
- :caption: /etc/taler/secrets/exchange-db.secret.conf
-
- [exchangedb-postgres]
- CONFIG=postgres:///taler-exchange
-
-
-If the database is run on a different host, please follow the instructions
-from the PostgreSQL manual for configuring remote access.
-
-After configuring the database credentials, the exchange database needs
-to be initialized with the following command:
-
-.. code-block:: shell-session
-
- [root@exchange-online]# sudo -u taler-exchange-httpd taler-exchange-dbinit
-
-Finally we need to grant the other accounts limited access:
-
-.. code-block:: shell-session
-
- [root@exchange-online]# sudo -u taler-exchange-httpd bash
- [taler-exchange-httpd@exchange-online]# echo 'GRANT SELECT,INSERT,UPDATE ON ALL TABLES IN SCHEMA public TO "taler-exchange-aggregator";' \
- | psql taler-exchange
- [taler-exchange-httpd@exchange-online]# echo 'GRANT SELECT,INSERT,UPDATE ON ALL TABLES IN SCHEMA public TO "taler-exchange-closer";' \
- | psql taler-exchange
- [taler-exchange-httpd@exchange-online]# echo 'GRANT SELECT,INSERT,UPDATE ON ALL TABLES IN SCHEMA public TO "taler-exchange-wire";' \
- | psql taler-exchange
- [taler-exchange-httpd@exchange-online]# echo 'GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO "taler-exchange-aggregator";' \
- | psql taler-exchange
- [taler-exchange-httpd@exchange-online]# echo 'GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO "taler-exchange-closer";' \
- | psql taler-exchange
- [taler-exchange-httpd@exchange-online]# echo 'GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO "taler-exchange-wire";' \
- | psql taler-exchange
- [taler-exchange-httpd@exchange-online]# exit
-
-.. note::
-
- The above instructions for changing database permissions only work *after*
- having initialized the database with ``taler-exchange-dbinit``, as
- the tables to exist before permissions can be granted on them. The
- ``taler-exchange-dbinit`` tool cannot setup these permissions, as it
- does not know which users will be used for which processes.
-
-
-Offline Signing Setup
-=====================
-
-The offline signing keys of the exchange should be stored on a different machine.
-The responsibilities of this offline signing machine are:
-
-* Generation of the exchange's offline master signing key.
-* Secure storage of the exchange's offline master signing key.
-* Generation of certificates (signed with the offline master signing key) that will be imported by the exchange.
-
-
-.. code-block:: shell-session
-
- [root@exchange-offline]# sudo -u taler-exchange-offline taler-exchange-offline setup
- < ... prints the exchange master public key >
-
-The public key printed as the output of this command must be put into the configuration
-of the online machine:
-
-.. code-block:: ini
- :caption: /etc/taler/conf.d/exchange-business.conf
-
- [exchange]
- MASTER_PUBLIC_KEY = YE6Q6TR1ED...
-
- # ... rest of file ...
-
-
-Exchange Web service / API Setup
-================================
-
-By default, the ``taler-exchange-httpd`` service listens for HTTP connections
-on a UNIX domain socket. To make the service publicly available, a reverse
-proxy such as nginx should be used. We strongly recommend to configure nginx
-to use TLS.
-
-The public URL that the exchange will be served under should
-be put in ``/etc/taler/conf.d/exchange-business.conf`` configuration file.
-
-.. code-block:: ini
- :caption: /etc/taler/conf.d/exchange-business.conf
-
- [exchange]
- BASE_URL = https://example.com/
-
- # ... rest of file ...
-
-The ``taler-exchange`` package ships with a sample configuration that can be
-enabled in nginx:
-
-.. code-block:: shell-session
-
- [root@exchange-online]# vim /etc/nginx/sites-available/taler-exchange
- < ... customize configuration ... >
- [root@exchange-online]# ln -s /etc/nginx/sites-available/taler-exchange \
- /etc/nginx/sites-enabled/taler-exchange
- [root@exchange-online]# systemctl reload nginx
-
-
-The exchange HTTP service can now be started:
-
-.. code-block:: shell-session
-
- [root@exchange-online]# systemctl start taler-exchange.target
-
-
-.. note::
-
- At this point, the exchange service is not yet fully operational.
-
-
-To check whether the exchange is running correctly under the advertized
-base URL, run:
-
-.. code-block:: shell-session
-
- [root@exchange-online]# export BASE_URL=$(taler-config -s exchange -o base_url)
- [root@exchange-online]# wget ${BASE_URL}management/keys
-
-The request might take some time to complete on slow machines, because
-a lot of key material will be generated.
-
-Offline Signing Procedure
-=========================
-
-The exchange HTTP service should be running now, but is not yet completely
-operational. To make the exchange HTTP service operational, the following
-steps involving the offline signing machine must be completed:
-
-1. The public keys of various online keys used by the exchange service are exported
- via a management HTTP API.
-2. The offline signing system validates this request and signs it.
- Additionally, the offline signing system signs policy messages
- to configure the exchange's bank accounts and associated fees.
-3. The messages generated by the offline signing system are uploaded
- via the management API of the exchange HTTP service.
-
-
-.. code-block:: shell-session
-
- [root@exchange-online]# taler-exchange-offline \
- download > sig-request.json
-
- [root@exchange-offline]# taler-exchange-offline \
- sign < sig-request.json > sig-response.json
- [root@exchange-offline]# taler-exchange-offline \
- enable-account payto://sepa/$IBAN?receiver-name=$NAME > acct-response.json
- [root@exchange-offline]# taler-exchange-offline \
- wire-fee 2021 sepa EUR:0 EUR:0 > fee-response.json
- [root@exchange-online]# taler-exchange-offline upload < sig-response.json
- [root@exchange-online]# taler-exchange-offline upload < acct-response.json
- [root@exchange-online]# taler-exchange-offline upload < fee-response.json
-
-
-
-
-Testing and Troubleshooting
-===========================
-
-The following shell session illustrates how the wallet can be used to withdraw
-electronic cash from the exchange and subsequently spend it. For these steps,
-a merchant backend is not required, as the wallet acts as a merchant.
-
-
-.. code-block:: shell-session
-
- # This will now output a payto URI that money needs to be sent to in order to allow withdrawal
- # of taler coins.
- $ taler-wallet-cli advanced withdraw-manually --exchange $EXCHANGE_URL --amount EUR:10.50
-
-
-Show the status of the manual withdrawal operation.
-
-.. code-block:: shell-session
-
- $ taler-wallet-cli transactions
-
-At this point, a bank transfer to the exchange's bank account
-needs to be made with the correct subject / remittance information
-as instructed by the wallet after the first step. With the
-above configuration, it should take about 5 minutes after the
-wire transfer for the incoming transfer to be observed by the
-Nexus.
-
-Run the following command to check whether the exchange received
-an incoming bank transfer:
-
-.. code-block:: shell-session
-
- [root@exchange-online]# taler-exchange-wire-gateway-client \
- --section exchange-accountcredentials-1 --credit-history
-
-Once the transfer has been made, try completing the withdrawal
-using:
-
-.. code-block:: shell-session
-
- $ taler-wallet-cli run-pending
-
-Afterwards, check the status of transactions and show the
-current wallet balance:
-
-.. code-block:: shell-session
-
- $ taler-wallet-cli transactions
- $ taler-wallet-cli balance
-
-
-Now, we can directly deposit coins via the exchange into a target
-account. (Usually, a payment is made via a merchant. The wallet
-provides this functionality for testing.)
-
-.. code-block:: shell-session
-
- $ taler-wallet-cli deposit create EUR:5 \
- payto://sepa/$IBAN?receiver-name=Name
- $ taler-wallet-cli run-pending
-
-
-Check if this transaction was successful (from the perspective
-of the wallet):
-
-.. code-block:: shell-session
-
- $ taler-wallet-cli transactions
-
-If the transaction failed, fix any open issue(s) with the exchange and
-run the "run-pending" command.
-
-The wallet can also track if the exchange wired the money to the merchant
-account. The "deposit group id" can be found in the output of the
-transactions list.
-
-.. code-block:: shell-session
-
- $ taler-wallet-cli deposit track $DEPOSIT_GROUP_ID
-
-You can also check using the exchange-tools whether the exchange sent
-the an outgoing transfer:
-
-.. code-block:: shell-session
-
- [root@exchange-online]# taler-exchange-wire-gateway-client \
- --section exchange-accountcredentials-1 --debit-history
-
-After enough time has passed, the money should arrive at the specified IBAN.
-
-
-FIXMEs
-======
-
-* We should have some summary with the inventory of services that should be
- running. Systemd by default doesn't show this nicely. Maybe suggest running
- "systemd list-dependencies taler-exchange.target"?
-* When multiple TWGs are configured, which one will be used by the taler-exchange-transfer? CG: ALL!
-
- * FD: Sure, for incoming transactions. But how does taler-exchange-transfer decide which TWG to use for an outgoing transaction?
-
-* What happens when the TWG doesn't like one particular outgoing transaction?
- How to recover from that as a sysadmin when it happens in practice?
diff --git a/taler-merchant-api-tutorial.rst b/taler-merchant-api-tutorial.rst
index 0be0f4e3..15e21e21 100644
--- a/taler-merchant-api-tutorial.rst
+++ b/taler-merchant-api-tutorial.rst
@@ -1,6 +1,6 @@
..
This file is part of GNU TALER.
- Copyright (C) 2014-2020 Taler Systems SA
+ Copyright (C) 2014-2023 Taler Systems SA
TALER 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
@@ -19,8 +19,12 @@
.. _merchant-api-tutorial:
-GNU Taler Merchant API Tutorial
-###############################
+Merchant API Tutorial
+#####################
+
+.. contents:: Table of Contents
+ :depth: 2
+ :local:
Introduction
============
@@ -63,10 +67,6 @@ If you want to look at some simple, running examples, check out these:
that accepts donations for software projects and gives donation
receipts.
-- The
- `survey <https://git.taler.net/taler-merchant-demos.git/tree/talermerchantdemos/survey>`__
- that gives users who answer a question a small reward.
-
- The `WooCommerce plugin <https://git.taler.net/gnu-taler-payment-for-woocommerce.git/>`__
which is a comprehensive integration into a Web shop including the refund business
process.
@@ -98,7 +98,7 @@ components:
The following image illustrates the various interactions of these key
components:
-.. image:: arch-api.png
+.. image:: images/arch-api.png
The backend provides the cryptographic protocol support, stores
Taler-specific financial information and communicates with the GNU Taler
@@ -125,13 +125,13 @@ configuration. See :doc:`taler-merchant-manual`.
The public sandbox backend https://backend.demo.taler.net/ uses an API
key in the ``Authorization`` header. The value of this header must be
-``ApiKey sandbox`` for the public sandbox backend.
+``Bearer secret-token:sandbox`` for the public sandbox backend.
.. code-block:: python
>>> import requests
- >>> requests.get("https://backend.demo.taler.net",
- ... headers={"Authorization": "ApiKey sandbox"})
+ >>> requests.get("https://backend.demo.taler.net/private/orders",
+ ... headers={"Authorization": "Bearer secret-token:sandbox"})
<Response [200]>
If an HTTP status code other than 200 is returned, something went wrong.
@@ -147,9 +147,9 @@ https://bank.demo.taler.net/.
Merchant Instances
------------------
-The same Taler merchant backend server can be used by multiple separate
+A single Taler merchant backend server can be used by multiple
merchants that are separate business entities. Each of these separate
-business entities is called a *merchant instance*, and is identified by
+business entities is assigned a *merchant instance* which is identified by
an alphanumeric *instance id*. If the instance is omitted, the instance
id ``default`` is assumed.
@@ -223,10 +223,10 @@ A minimal Python snippet for creating an order would look like this:
>>> body = dict(order=dict(amount="KUDOS:10",
... summary="Donation",
... fulfillment_url="https://example.com/thanks.html"),
- ... create_token=false)
- >>> response = requests.post("https://backend.demo.taler.net/private/order",
+ ... create_token=False)
+ >>> response = requests.post("https://backend.demo.taler.net/private/orders",
... json=body,
- ... headers={"Authorization": "ApiKey sandbox"})
+ ... headers={"Authorization": "Bearer secret-token:sandbox"})
<Response [200]>
@@ -244,19 +244,23 @@ address of the merchant instance. The full details are called the
you must adjust the code to construct the ``taler://pay/`` URI
given below to include the claim token.
-After successfully ``POST``\ ing to ``/private/orders``, an ``order_id`` will be
-returned. Together with the merchant ``instance``, the order id uniquely
-identifies the order within a merchant backend. Using the order ID, you
-can trivially construct the respective ``taler://pay/`` URI that must
-be provided to the wallet. Let ``example.com`` be the domain name where
-the public endpoints of the instance are reachable. The Taler pay URI is
-then simply ``taler://pay/example.com/$ORDER_ID/`` where ``$ORDER_ID``
-must be replaced with the ID of the order that was returned.
+After successfully ``POST``\ ing to ``/private/orders``, a JSON with just an
+``order_id`` field with a string representing the order ID will be returned.
+If you also get a claim token, please double-check that you used the request
+as described above.
+
+Together with the merchant ``instance``, the order id uniquely identifies the
+order within a merchant backend. Using the order ID, you can trivially
+construct the respective ``taler://pay/`` URI that must be provided to the
+wallet. Let ``example.com`` be the domain name where the public endpoints of
+the instance are reachable. The Taler pay URI is then simply
+``taler://pay/example.com/$ORDER_ID/`` where ``$ORDER_ID`` must be replaced
+with the ID of the order that was returned.
You can put the ``taler://`` URI as the target of a link to open the Taler
wallet via the ``taler://`` schema, or put it into a QR code. However, for a
Web shop, the easiest way is to simply redirect the browser to
-``https://example.com/orders/$ORDER_ID/``. That page will then trigger the
+``https://example.com/orders/$ORDER_ID``. That page will then trigger the
Taler wallet. Here the backend generates the right logic to trigger the
wallet, supporting the various types of Taler wallets in existence. Instead
of constructing the above URL by hand, it is best to obtain it by checking for
@@ -267,11 +271,11 @@ Checking Payment Status and Prompting for Payment
-------------------------------------------------
Given the order ID, the status of a payment can be checked with the
-``/private/orders/$ORDER_ID/`` endpoint. If the payment is yet to be completed
+``/private/orders/$ORDER_ID`` endpoint. If the payment is yet to be completed
by the customer, ``/private/orders/$ORDER_ID`` will give the frontend a URL
(under the name ``payment_redirect_url``) that will trigger the customer’s
wallet to execute the payment. This is basically the
-``https://example.com/orders/$ORDER_ID/`` URL we discussed above.
+``https://example.com/orders/$ORDER_ID`` URL we discussed above.
Note that the best way to obtain the ``payment_redirect_url`` is to check the
status of the payment, even if you know that the user did not pay yet. There
@@ -282,7 +286,7 @@ backend to do it is the safest method.
>>> import requests
>>> r = requests.get("https://backend.demo.taler.net/private/orders/" + order_id,
- ... headers={"Authorization": "ApiKey sandbox"})
+ ... headers={"Authorization": "Bearer secret-token:sandbox"})
>>> print(r.json())
If the ``order_status`` field in the response is ``paid``, you will not
@@ -350,12 +354,12 @@ This code snipped illustrates giving a refund:
... reason="Customer did not like the product")
>>> requests.post("https://backend.demo.taler.net/private/orders/"
... + order_id + "/refund", json=refund_req,
- ... headers={"Authorization": "ApiKey sandbox"})
+ ... headers={"Authorization": "Bearer secret-token:sandbox"})
<Response [200]>
.. Note::
After granting a refund, the public
- ``https://example.com/orders/$ORDER_ID/`` endpoint will
+ ``https://example.com/orders/$ORDER_ID`` endpoint will
change its wallet interaction from requesting payment to
offering a refund. Thus, frontends may again redirect
browsers to this endpoint. However, to do so, a
@@ -372,8 +376,6 @@ This code snipped illustrates giving a refund:
Repurchase detection and fulfillment URLs
=========================================
-.. TODO:: This section needs to be reviewed for 0.8.
-
A possible problem for merchants selling access to digital articles
is that a customer may have paid for an article on one device, but
may then want to read it on a different device, possibly one that
@@ -411,79 +413,11 @@ considered to identify a resource you can pay for and thus do not have to be
unique.
-.. _Giving-Customers-Tips:
-.. index:: tips
-
-Giving Customers Tips
-=====================
-
-.. TODO:: This section needs to be updated for 0.8.
-
-
-GNU Taler allows Web sites to grant small amounts directly to the
-visitor. The idea is that some sites may want incentivize actions such
-as filling out a survey or trying a new feature. It is important to note
-that tips are not enforceable for the visitor, as there is no contract.
-It is simply a voluntary gesture of appreciation of the site to its
-visitor. However, once a tip has been granted, the visitor obtains full
-control over the funds provided by the site.
-
-The “merchant” backend of the site must be properly configured for
-tipping, and sufficient funds must be made available for tipping See
-Taler Merchant Operating Manual.
-
-To check if tipping is configured properly and if there are sufficient
-funds available for tipping, query the ``/tip-query`` endpoint:
-
-.. code-block:: python
-
- >>> import requests
- >>> requests.get("https://backend.demo.taler.net/tip-query?instance=default",
- ... headers={"Authorization": "ApiKey sandbox"})
- <Response [200]>
-
-.. _authorize-tip:
-
-To authorize a tip, ``POST`` to ``/tip-authorize``. The following fields
-are recognized in the JSON request object:
-
-- ``amount``: Amount that should be given to the visitor as a tip.
-
-- ``instance``: Merchant instance that grants the tip (each instance may
- have its own independent tipping funds configured).
-
-- ``justification``: Description of why the tip was granted. Human-readable
- text not exposed to the customer, but used by the Back Office.
-
-- ``next_url``: The URL that the user’s browser should be redirected to by
- the wallet, once the tip has been processed.
-
-The response from the backend contains a ``tip_redirect_url``. The
-customer’s browser must be redirected to this URL for the wallet to pick
-up the tip.
-
-.. _pick-up-tip:
-
-This code snipped illustrates giving a tip:
-
-.. code-block:: python
-
- >>> import requests
- >>> tip_req = dict(amount="KUDOS:0.5",
- ... instance="default",
- ... justification="User filled out survey",
- ... next_url="https://merchant.com/thanks.html")
- >>> requests.post("https://backend.demo.taler.net/tip-authorize", json=tip_req,
- ... headers={"Authorization": "ApiKey sandbox"})
- <Response [200]>
-
.. _Advanced-topics:
Advanced topics
===============
-.. TODO:: This section needs to be updated for 0.8.
-
.. _Session_002dBound-Payments:
Session-Bound Payments
diff --git a/taler-merchant-manual.rst b/taler-merchant-manual.rst
index d5b9fcc7..353885cd 100644
--- a/taler-merchant-manual.rst
+++ b/taler-merchant-manual.rst
@@ -1,7 +1,30 @@
-.. _ffoobar:
+..
+ This file is part of GNU TALER.
+
+ Copyright (C) 2014-2023 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Christian Grothoff
+
+.. _taler-merchant-backend-operator-manual:
+
+Merchant Backend Operator Manual
+################################
+
+.. contents:: Table of Contents
+ :depth: 1
+ :local:
-GNU Taler Merchant Backend Operator Manual
-##########################################
Introduction
============
@@ -9,20 +32,8 @@ Introduction
About GNU Taler
---------------
-GNU Taler is an open protocol for an electronic payment system with a
-free software reference implementation. GNU Taler offers secure, fast
-and easy payment processing using well understood cryptographic
-techniques. GNU Taler allows customers to remain anonymous, while
-ensuring that merchants can be held accountable by governments. Hence,
-GNU Taler is compatible with anti-money-laundering (AML) and
-know-your-customer (KYC) regulation, as well as data protection
-regulation (such as GDPR).
-
-GNU Taler is not yet production-ready: after following this manual you
-will have a backend that can process payments in “KUDOS”, but not
-regular currencies. This is not so much because of limitations in the
-backend, but because we are not aware of a Taler exchange operator
-offering regular currencies today.
+.. include:: frags/about-taler.rst
+
.. _About-this-manual:
@@ -36,17 +47,6 @@ We expect some moderate familiarity with the compilation and
installation of Free Software packages. An understanding of cryptography
is not required.
-This first chapter of the manual will give a brief overview of the
-overall Taler architecture, describing the environment in which the
-Taler backend operates. The second chapter then explains how to install
-the software, including key dependencies. The third chapter will explain
-how to configure the backend, including in particular the configuration
-of the bank account details of the merchant.
-
-The last chapter gives some additional information about advanced topics
-which will be useful for system administrators but are not necessary for
-operating a basic backend.
-
.. _Architecture-overview:
Architecture overview
@@ -56,20 +56,19 @@ Architecture overview
.. index:: KUDOS
Taler is a pure payment system, not a new crypto-currency. As such, it
-operates in a traditional banking context. In particular, this means
-that in order to receive funds via Taler, the merchant must have a
-regular bank account, and payments can be executed in ordinary
-currencies such as USD or EUR. For testing purposes, Taler uses a
-special currency “KUDOS” and includes its own special bank.
+operates in a traditional banking context. In particular, this means that in
+order to receive funds via Taler, the merchant must have a regular bank
+account, and payments can be executed in ordinary currencies such as USD or
+EUR. Taler can also be used as a regional currency; for such scenarios, the
+Taler system also includes its own stand-alone bank.
.. index:: frontend
.. index:: back-office
.. index:: backend
.. index:: DBMS
-.. index:: Postgres
+.. index:: PostgreSQL
-The Taler software stack for a merchant consists of four main
-components:
+The Taler software stack for a merchant consists of four main components:
- A *frontend* which interacts with the customer’s browser. The frontend
enables the customer to build a shopping cart and place an order.
@@ -90,14 +89,14 @@ components:
describes how to install and configure this backend.
- A *DBMS* which stores the transaction history for the Taler backend.
For now, the GNU Taler reference implementation only supports
- Postgres, but the code could be easily extended to support another
- DBMS. Please review the Postgres documentation for details on
+ PostgreSQL, but the code could be easily extended to support another
+ DBMS. Please review the PostgreSQL documentation for details on
how to configure the database.
The following image illustrates the various interactions of these key
components:
-.. image:: arch-api.png
+.. image:: images/arch-api.png
.. index:: RESTful
@@ -107,13 +106,13 @@ Taler exchange over the Internet. The frontend accesses the backend via a
RESTful API. As a result, the frontend never has to directly communicate with
the exchange, and also does not deal with sensitive data. In particular, the
merchant’s signing keys and bank account information are encapsulated within
-the Taler backend.
+the Taler merchant backend.
A typical deployment will additionally include a full-blown Web server (like
Apache or Nginx). Such a Web server would be responsible for TLS termination and
access control to the ``/private/`` and ``/management/`` API endpoints of the
-merchant backend. Please carefully review the section on :ref:`Secure setup
-<Secure-setup>` before deploying a Taler merchant backend to production.
+merchant backend. Please carefully review the section on :ref:`secure setup
+<Secure-setup>` before deploying a Taler merchant backend into production.
Terminology
@@ -126,21 +125,44 @@ Instances
.. index:: instance
-The backend allows the user to run multiple *instances* of shops with distinct
-business entities sharing a single backend. Each instance uses its own bank
-accounts and key for signing contracts. All major accounting functionality is
-separate per instance. What is shared is the database, HTTP(S) address and
-the main Taler configuration (accepted currency, exchanges and auditors).
+The backend allows a single HTTP server to support multiple independent shops
+with distinct business entities sharing a single backend. An *instance* is
+the name or identifier that allows the single HTTP server to determine which
+shop a request is intended for. Each instance has its own base URL in the
+REST API of the merchant backend (``/instances/$INSTANCE/``). Each instance
+can use its own bank accounts and keys for signing contracts. All major
+accounting functionality is separate per instance. Access to each instance is
+controlled via a bearer token (to be set in the HTTP "Authorization" header).
+All instances share the same *database*, top-level HTTP(S) address and the
+main Taler configuration (especially the accepted *currency* and *exchanges*).
-Accounts
---------
+ .. note::
+
+ This documentation does not use the term "user" or "username" in
+ conjunction with instances as that might create confusion between
+ instances with paying customers using the system. We also do not use the
+ term "account" in conjunction with instances, as that might cause
+ confusion with bank accounts. That said, conceptually it is of course
+ acceptable to consider instances to be the "users" or "accounts" of a
+ merchant backend and the bearer token is equivalent to a passphrase.
+
+.. _instance-bank-account:
+
+Instance Bank Accounts
+----------------------
-.. index:: account
+.. index:: Bank account
To receive payments, an instance must have configured one or more bank
-*accounts*. The backend does not have accounts for users, and instances are
-also not really 'accounts'. So whenever we use the term *account*, it is about
-a bank account of a merchant.
+*accounts*. When configuring the bank account of an instance, one should
+ideally also provide the address and credentials of an HTTP service
+implementing the :ref:`Taler Bank Revenue HTTP API
+<taler-bank-merchant-http-api>`. Given such a service, the GNU Taler merchant
+backend can automatically reconcile wire transfers from the exchange to the
+merchant's bank account with the orders that are being settled.
+
+This documentation exclusively uses the term *account* for the bank
+accounts of a merchant or shop that may be associated with an instance.
Inventory
---------
@@ -153,21 +175,26 @@ Inventory
The Taler backend offers inventory management as an optional function.
Inventory is tracked per instance and consists of *products* sold in
-*units*. Inventory can be finite or infinite (for digital products).
-Products may include previews (images) to be shown to the user and other
-meta-data. Inventory management allows the frontend to *lock* products,
-reserving them for a particular (unpaid) *order*. The backend can keep
-track of how many units of a product remain in stock and ensure that
-the number of units sold does not exceed the number of units in stock.
+*units*. Inventory can be finite (physical stock) or infinite (for digital
+products). Products may include previews (images) to be shown to the user as
+well as other meta-data. Inventory management allows the frontend to *lock*
+products, reserving a number of units from stock for a particular (unpaid)
+*order*. The backend can keep track of how many units of a product remain in
+stock and ensure that the number of units sold does not exceed the number of
+units in stock.
Inventory management is optional, and it is possible for the frontend to
-include products in orders that are not in the inventory, or to override
-prices of products in the inventory.
+include products in orders that are not in the inventory. The frontend
+can also override prices of products in the inventory or set a total price
+for an order that is different from the price of the sum of the products
+in the order.
+
Orders and Contracts
--------------------
.. index:: order
+.. index:: terms
.. index:: contract
.. index:: claim
.. index:: pay
@@ -176,8 +203,13 @@ Orders and Contracts
.. index:: lock
.. index:: legal expiration
-In Taler, users pay merchants for orders. An order is first created by the
-merchant, where the merchant specifies the specific terms of the order.
+In Taler, users pay merchants for *orders*. An order is first created by the
+merchant. To create an order, the merchant must specify the specific *terms*
+of the order. Order *terms* include details such as the total amount to be
+paid, payment fees the merchant is willing to cover, the set of products to
+deliver, a delivery location and many other details. The `merchant API
+specification <contract-terms>`_ specifies the full set of possible order
+terms.
After an order is created, it is *claimed* by a wallet. Once an order is
claimed by a specific wallet, only that wallet will be able to pay for this
@@ -189,277 +221,216 @@ purchase the same product.
To prevent unauthorized wallets from claiming an order, merchants can specify
that claims require authorization in the form of a *claim token*. This is
useful in case the order ID is predictable (say because an existing order ID
-scheme from the merchant frontend is used) and at the same time malicious
-actors claiming orders is problematic (say because of limited stocks). The use
-of claim tokens is optional, but if a claim token is used, it must be provided
-to the wallet as part of the order URI.
-
-Additionally, when stocks are limited, you can configure Taler to
-set a *product lock* on items (say, while composing the shopping cart).
-These locks, as well as the *order lock* (when the order is complete),
-can be configured to auto-unlock at certain times.
-
-.. FIXME: Is "can be configured" correct? (Are there controls surfaced?)
-
-A wallet may *pay* for a claimed order, at which point the order turns into
-a (paid) contract. Orders have an expiration date after which the commercial
-offer expires and any stock of products *locked* by the order is released,
-allowing the stock to be sold in other orders.
+scheme with predictable order IDs from the merchant frontend is used) and at
+the same time malicious actors claiming orders is problematic (say because of
+limited stocks). The use of claim tokens is optional, but if a claim token is
+used, it must be provided to the wallet as part of the order URI.
+
+Additionally, when stocks are limited, you can configure Taler to set a
+*product lock* on items (say, while composing the shopping cart). These
+locks will ensure that the limited stock is respected when making offers
+to consumers.
+
+A wallet may *pay* for a claimed order, at which point the order turns into a
+(paid) *contract*. Orders have a configurable expiration date (the
+``pay_deadline``) after which the commercial offer expires and any stock of
+products *locked* by the order will be automatically released, allowing the
+stock to be sold in other orders. When an unpaid order expires, the customer
+must request a fresh order if they still want to make a purchase.
Once a contract has been paid, the merchant should fulfill the contract. It
is possible for the merchant to *refund* a contract order, for example if the
contract cannot be fulfilled after all. Refunds are only possible after the
customer paid and before the exchange has *wired* the payment to the
merchant. Once the funds have been wired, refunds are no longer allowed by the
-Taler exchange. The *wire deadline* specifies the latest time by which an
-exchange must wire the funds, while the (earlier) *refund deadline* specifies
-the earliest time when an exchange may wire the funds.
+Taler exchange. The *wire deadline* specifies the latest point in time by
+which an exchange must wire the funds, while the (earlier) *refund deadline*
+specifies the earliest point in time when an exchange may wire the funds.
+Thus, refunds are always possible between the time of purchase and the
+refund deadline, but may remain possible until the wire deadline.
-Contract information is kept for legal reasons, typically to provide tax
-records in case of a tax audit. After the *legal expiration* (by default a
-decade), contract information is deleted.
+Contract information is kept for legal reasons in the merchant database. The
+main legal reason is typically to provide tax records in case of a tax audit.
+After the *legal expiration* (by default: a decade), contract information is
+deleted when running the garbage collector using ``taler-merchant-dbinit``.
-Transfers
----------
-
-.. index:: transfer
-.. index:: wire transfer
-
-The Taler backend can be used to verify that the exchange correctly wired all
-of the funds to the merchant. However, the backend does not have access to the
-incoming wire transfers of the merchant's bank account. Thus, merchants must
-manually provide the backend with wire *transfer* data that specifies the wire
-transfer subject and the amount that was received. Given this information, the
-backend can detect and report any irregularities that might arise.
-
-Tipping
--------
-
-.. index:: tip
-.. index:: grant
-.. index:: pick up
-
-Taler does not only allow a Website to be paid, but also to make voluntary,
-non-contractual payments to visitors, called *tips*. Such tips could be
-granted as a reward for filling in surveys or watching advertizements. For
-tips, there is no contract, tips are always voluntary actions by the Web
-site that do not arise from a contractual obligation. Before a Web site
-can create tips, it must establish a reserve. Once a reserve has been
-established, the merchant can *grant* tips, allowing wallets to *pick up*
-the tip.
-
-Reserves
---------
-
-.. index:: reserve
-.. index:: close
-
-A *reserve* is a pool of electronic cash at an exchange under the control of
-a private key. Merchants withdraw coins from a reserve when granting
-tips. A reserve is established by first generating the required key material
-in the merchant backend, and then wiring the desired amount of funds to the
-exchange.
-
-An exchange will automatically *close* a reserve after a fixed period of time
-(typically about a month), wiring any remaining funds back to the merchant.
+.. _template:
-Installation
-============
-
-This chapter describes how to install the GNU Taler merchant backend.
-
-.. _Generic-instructions:
+Templates
+---------
-Generic instructions for installation from source
--------------------------------------------------
+.. index:: Template
-This section provides generic instructions for the merchant backend
-installation independent of any particular operating system. Operating
-system specific instructions are provided in the following sections. You
-should follow the operating system specific instructions if those are
-available, and only consult the generic instructions if no
-system-specific instructions are provided for your specific operating
-system.
+Usually, a merchant must use an authenticated endpoint to create an order and
+then share the link to the order with a wallet. Templates are a mechanism that
+allows wallets to create their own orders directly, using a public endpoint.
+The template fixes some properties of the contracts created from it, while
+other details may be left for the customer to provide. Templates are useful
+in cases where the point-of-sale of a merchant is offline (and thus cannot
+setup an order), or even in cases where a simple static QR code is desired to
+accept payments or donations.
-.. _Installation-of-dependencies:
+When generating a template, the "summary" text of the contract and the
+"amount" to be paid by the customer can be fixed or left for the customer to
+specify. If the customer is expected to provide either or both of these
+values, the template link (or QR code) can specify a default value. For
+example, a cafeteria with a fixed price lunch may use a "lunch" template with
+both values fixed to the lunch price and the "lunch" product, a bakery might
+fix the summary to "baked goods" but allow the customer to enter the amount
+based on the total price of the items being bought, and a charity may allow
+donating an arbitrary amount and summary message while also suggesting default
+values.
-Installation of dependencies
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+If an offline merchant wants to confirm that a customer did actually pay the
+agreed amount using an order derived from a template, they can associate an
+OTP device with the template.
-The following packages need to be installed before we can compile the
-backend:
-.. include:: frags/list-of-dependencies.rst
+.. _otp-device:
-- GNU Taler exchange (see `release announcement <https://mail.gnu.org/archive/cgi-bin/namazu.cgi?query=taler&idxname=info-gnu&max=20&result=normal&sort=date:late>`__)
+OTP Devices
+-----------
-Except for the last two, these are available in most GNU/Linux distributions
-and should just be installed using the respective package manager. Be careful
-with GNU libmicrohttpd; here, some distributions only include an older version
-that will not work.
+.. index:: OTP
+.. index:: TOTP
-While you are in the GNU Taler exchange
-`download directory <http://ftpmirror.gnu.org/taler/>`__,
-you might as well also download the tarball for GNU Taler merchant.
+A One-Time-Password (OTP) generator is a device or application that generates
+a 4 to 8 digit code typically used for authentication. The widely used TOTP
+standard is described in `RFC 6238 <https://www.rfc-editor.org/rfc/rfc6238>`_.
+For GNU Taler merchant backends, OTP devices are used as a way to assure a
+merchant without network connectivity that a customer made a digital
+payment. The idea is described in depth in our `SUERF Policy Brief
+<https://www.suerf.org/suer-policy-brief/69851/practical-offline-payments-using-one-time-passcodes>`_.
+To use this method, a merchant must configure the OTP device's shared secret
+in the merchant backend, and then associate the OTP device with a
+:ref:`template`. Once the customer has paid, they are given a list of OTP
+codes which must be shown to the merchant who can check that at least one of
+the codes matches their OTP device, proving that the customer made the
+payment.
-GNU Taler components version numbers follow the ``MAJOR.MINOR.MICRO`` format.
-The general rule for compatibility is that ``MAJOR`` and ``MINOR`` must match.
-Exceptions to this general rule are documented in the release notes.
-For example, Taler merchant 0.8.0 is compatible with Taler exchange 0.8.1.
-The following sections will provide detailed instructions for installing
-the ``libgnunetutil`` and GNU Taler exchange dependencies.
+Transfers
+---------
-.. _Installing-libgnunetutil:
+.. index:: transfer
+.. index:: wire transfer
-Installing GNUnet
-^^^^^^^^^^^^^^^^^
+The Taler backend can be used to verify that the exchange correctly wired all
+of the funds to the merchant. However, if no :ref:`Taler Bank Revenue HTTP API
+<taler-bank-merchant-http-api>` was provided for the respective bank account,
+the backend does not have access to the incoming wire transfers of the
+merchant's bank account. In this case, merchants should manually provide the
+backend with wire *transfer* data that specifies the *wire transfer subject*
+and the amount that was received. Given this information, the backend can
+detect and report any irregularities that might arise.
-.. index:: GNUnet
-.. include:: frags/installing-gnunet.rst
+Webhooks
+--------
-There is no need to actually run a GNUnet peer to use the Taler merchant
-backend -- all the merchant needs from GNUnet is a number of headers and
-libraries!
+.. index:: webhook
+A webhook is a pre-defined HTTP request that the GNU Taler merchant backend
+will make upon certain events, such as an order being paid or refunded. When
+the configured event happens, the merchant backend will make an HTTP request
+to the endpoint configured in the webhook configuration, possibly sending
+selected data about the event to the respective Web service. Webhooks can be
+used to trigger additional business logic outside of the GNU Taler merchant
+backend.
-.. _Installing-the-GNU-Taler-exchange:
-Installing the GNU Taler exchange
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Installation
+============
-.. index:: exchange
+This chapter describes how to install the GNU Taler merchant backend.
-.. include:: frags/installing-taler-exchange.rst
+.. _Generic-instructions:
-There is no need to actually run a Taler exchange to use the Taler merchant
-backend -- all the merchant needs from the Taler exchange is a few headers and
-libraries!
+Installing the GNU Taler binary packages on Debian
+--------------------------------------------------
+.. include:: frags/installing-debian.rst
-.. _Installing-the-GNU-Taler-merchant-backend:
+.. include:: frags/apt-install-taler-merchant.rst
-Installing the GNU Taler merchant backend
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. index:: backend
+Installing the GNU Taler binary packages on Trisquel
+----------------------------------------------------
-.. include:: frags/installing-taler-merchant.rst
+.. include:: frags/installing-trisquel.rst
-Installing the GNU Taler binary packages on Debian
+Installing the GNU Taler binary packages on Ubuntu
--------------------------------------------------
-.. include:: frags/installing-debian.rst
+.. include:: frags/installing-ubuntu.rst
.. include:: frags/apt-install-taler-merchant.rst
-Installing the GNU Taler binary packages on Ubuntu
---------------------------------------------------
+Installing from source
+----------------------
-.. include:: frags/installing-ubuntu.rst
+The following instructions will show how to install a GNU Taler
+merchant backend from source.
-.. include:: frags/apt-install-taler-merchant.rst
+The package sources can be find in our
+`download directory <http://ftpmirror.gnu.org/taler/>`__.
+.. include:: frags/semver.rst
-.. _Installing-Taler-on-Debian-GNU_002fLinux:
+First, the following packages need to be installed before we can compile the
+backend:
-Installing Taler on Debian GNU/Linux from source
-------------------------------------------------
+.. include:: frags/list-of-dependencies.rst
-.. index:: Wheezy
-.. index:: Jessie
-.. index:: Stretch
-.. index:: Debian
+.. include:: frags/installing-gnunet.rst
-Debian Wheezy is too old and lacks most of the packages required.
-Debian Jessie is better, but still lacks PostgreSQL 9.6.
+.. include:: frags/install-before-check.rst
-On Debian Stretch, only GNU libmicrohttpd needs to be compiled from
-source. To install dependencies on Debian stretch, run the following
-commands:
+There is no need to actually run a GNUnet peer to use the Taler merchant
+backend -- all the merchant needs from GNUnet is a number of headers and
+libraries!
-.. code-block:: console
+.. include:: frags/installing-taler-exchange.rst
- # apt-get install \
- libqrencode-dev \
- libsqlite3-dev \
- libltdl-dev \
- libunistring-dev \
- libsodium-dev \
- libargon2-0-dev \
- libcurl4-gnutls-dev \
- libgcrypt20-dev \
- libjansson-dev \
- libpq-dev \
- postgresql-9.6
- # wget https://ftp.gnu.org/gnu/libmicrohttpd/libmicrohttpd-latest.tar.gz
- # wget https://ftp.gnu.org/gnu/libmicrohttpd/libmicrohttpd-latest.tar.gz.sig
- # gpg -v libmicrohttpd-latest.tar.gz # Should show signed by 939E6BE1E29FC3CC
- # tar xf libmicrohttpd-latest.tar.gz
- # cd libmicrohttpd-0*
- # ./configure
- # make install
-
-For more recent versions of Debian, you should instead run:
+There is no need to actually run a Taler exchange to use the Taler merchant
+backend -- all the merchant needs from the Taler exchange is a few headers and
+libraries!
-.. code-block:: console
+.. include:: frags/install-before-check.rst
- # apt-get install \
- libqrencode-dev \
- libsqlite3-dev \
- libltdl-dev \
- libunistring-dev \
- libsodium-dev \
- libargon2-dev \
- libcurl4-gnutls-dev \
- libgcrypt20-dev \
- libjansson-dev \
- libpq-dev \
- postgresql-9.6 \
- libmicrohttpd-dev
+.. include:: frags/installing-taler-merchant.rst
-Note that Stretch requires ``libargon2-0-dev``,
-while later versions of Debian require ``libargon2-dev``.
+.. include:: frags/install-before-check.rst
-For the rest of the installation, follow the generic installation
-instructions starting with the installation of libgnunetutil. Note that
-if you used the Debian Stretch instructions above, you need to pass
-``--with-microhttpd=/usr/local/`` to all ``configure`` invocations.
-How to configure the merchant’s backend
-=======================================
+How to configure the merchant backend
+=====================================
-.. index:: taler-config
.. index:: taler.conf
The installation already provides reasonable defaults for most of the
configuration options. However, some must be provided, in particular the
-database account and bank account that the backend should use. By
-default, the file ``$HOME/.config/taler.conf`` is where the Web shop
-administrator specifies configuration values that augment or override
-the defaults. The format of the configuration file is the well-known INI
-file format. You can edit the file by hand, or use the ``taler-config``
-commands given as examples.
+database that the backend should use. By default, the file
+``$HOME/.config/taler.conf`` is where the Web shop administrator specifies
+configuration values that augment or override the defaults.
+Note that when using our binary packages, the systemd service files
+force the use of ``/etc/taler/taler.conf`` as the main configuration file.
.. include:: frags/configuration-format.rst
-.. include:: frags/using-taler-config.rst
-
-
.. _Backend-options:
Backend options
---------------
.. index:: DBMS
-.. index:: Postgres
+.. index:: PostgreSQL
.. index:: UNIX domain socket
.. index:: TCP
.. index:: port
@@ -470,25 +441,30 @@ Backend options
.. index:: wire format
The following table describes the options that commonly need to be
-modified. Here, the notation ``[$section]/$option`` denotes the option
-``$option`` under the section ``[$section]`` in the configuration file.
+modified. Here, the notation ``[$SECTION]/$OPTION`` denotes the option
+``$OPTION`` under the section ``[$SECTION]`` in the configuration file.
Service address
^^^^^^^^^^^^^^^
-The following option sets the transport layer address used by the
-merchant backend:
+The service address specifies where the taler-merchant-httpd should listen for
+requests. When using the Debian/Ubuntu packages, these options will already be
+configured correctly for the included Nginx and Apache configurations and will
+not need any changes.
+
+The following option sets the transport protocol used by the merchant backend:
.. code-block:: ini
- [MERCHANT]/SERVE = TCP | UNIX
+ [MERCHANT]
+ SERVE = unix # or tcp
-If given,
+If this option is set to
-- ``TCP``, then we need to set the TCP port in ``[MERCHANT]/PORT``
+- ``tcp`` then we need to set the TCP port in ``[MERCHANT]/PORT``;
-- ``UNIX``, then we need to set the unix domain socket path and mode
+- ``unix`` then we need to set the unix domain socket path and mode
in ``[MERCHANT]/UNIXPATH`` and ``[MERCHANT]/UNIXPATH_MODE``. The
latter takes the usual permission mask given as a number, e.g. 660
for user/group read-write access.
@@ -500,23 +476,26 @@ the backend to the network.
To run the Taler backend on TCP port 8888, use:
-.. code-block:: console
+.. code-block:: ini
- $ taler-config -s MERCHANT -o SERVE -V TCP
- $ taler-config -s MERCHANT -o PORT -V 8888
+ [MERCHANT]
+ SERVE = tcp
+ PORT = 8888
.. note::
- When using the Debian/Ubuntu packages, these options are already
- configured in the ``/etc/taler/conf.d/merchant.conf`` configuration file.
+ If you need to change where the taler-merchant-httpd listens for requests,
+ you should edit ``/etc/taler/merchant-overrides.conf``. By default, the
+ Taler merchant package will use a UNIX domain socket at
+ ``/run/taler/merchant-httpd/merchant-http.sock``. For the best possible
+ security it is recommended to leave this in place and configure a reverse
+ proxy (Nginx or Apache) as described below.
- If you need to change them, you should edit ``/etc/taler/merchant-overrides.conf``,
- for example by passing ``-c /etc/taler/merchant-overrides.conf`` to the
- ``taler-config`` commands above. By default, the Taler merchant
- package when installed on Debian/Ubuntu will use a UNIX domain socket
- at ``/run/taler/merchant-httpd/merchant-http.sock``. For the best possible
- security, it is recommended to leave this in place and configure a reverse
- proxy (nginx or Apache) as described below.
+ When using the Debian/Ubuntu packages, the use of a UNIX domain socket
+ is already pre-configured in the ``/etc/taler/conf.d/merchant.conf``
+ configuration file. Suitable reverse proxy configuration
+ file templates (``taler-merchant``) are be installed in the
+ respective ``sites-available`` directories of Apache and Nginx.
@@ -528,15 +507,17 @@ specified using the option
.. code-block:: ini
- [TALER]/CURRENCY
+ [TALER]
+ CURRENCY = EUR # or USD, ...
-For testing purposes, the currency MUST match “KUDOS” so that tests
-will work with the Taler demonstration exchange at
-https://exchange.demo.taler.net/:
+When testing with the Taler demonstration exchange at
+https://exchange.demo.taler.net/ you must set this
+value to ``KUDOS``:
-.. code-block:: console
+.. code-block:: ini
- $ taler-config -s TALER -o CURRENCY -V KUDOS
+ [TALER]
+ CURRENCY = KUDOS
.. note::
@@ -556,7 +537,8 @@ The option
.. code-block:: ini
- [MERCHANT]/DB
+ [MERCHANT]
+ DB = postgres
specifies which DBMS is to be used. However, currently only the value
``postgres`` is supported. This is also the default.
@@ -566,29 +548,30 @@ DBMS-specific options to access the database.
.. note::
- When using the Debian/Ubuntu packages, the database should already
- be configured in the ``/etc/taler/secrets/merchant-db.secret.conf``
- configuration file. The ``talermerchant`` database is also already
- configured (unless you answered ``no`` when asked the question during
- installation), so you can skip everything in this section.
+ The **taler-merchant-dbconfig** tool can be used to automate the database
+ setup. When using the Debian/Ubuntu packages, the user should already have
+ been created, so you can just run the tool without any arguments and should
+ have a working database configuration.
+
-For the ``postgres`` backend, you need to provide:
+For the ``postgres`` backend, you need to specify:
.. code-block:: ini
- [MERCHANTDB-postgres]/CONFIG
+ [merchantdb-postgres]
+ CONFIG = "postgres:///talermerchant"
-This option specifies a postgres access path using the format
-``postgres:///$DBNAME``, where ``$DBNAME`` is the name of the
-Postgres database you want to use. Suppose ``$USER`` is the name of
-the user who will run the backend process. Then, you need to first
-run:
+This option specifies a PostgreSQL access path, typically using the format
+``postgres:///$DBNAME``, where ``$DBNAME`` is the name of the PostgreSQL
+database you want to use (here, ``talermerchant`` on the local machine).
+Suppose ``$USER`` is the name of the user who will run the backend process
+(usually ``taler-merchant-httpd``). Then, you need to first run:
.. code-block:: console
$ sudo -u postgres createuser -d $USER
-as the Postgres database administrator (usually ``postgres``) to
+as the PostgreSQL database administrator (usually ``postgres``) to
grant ``$USER`` the ability to create new databases. Next, you should
as ``$USER`` run:
@@ -599,29 +582,18 @@ as ``$USER`` run:
to create the backend’s database. Here, ``$DBNAME`` must match the
database name given in the configuration file.
-To configure the Taler backend to use this database, run:
-
-.. code-block:: console
-
- $ taler-config -s MERCHANTDB-postgres -o CONFIG \
- -V postgres:///$DBNAME
-
-Now you should create the tables and indices. To do this, run as ``$USER``:
+Now you should be able to create the tables and indices. To do this, run as
+``$USER`` (usually ``taler-merchant-httpd``):
.. code-block:: console
$ taler-merchant-dbinit
-
-You can improve your security posture if you now REVOKE the rights to CREATE,
+You may improve your security posture if you now REVOKE the rights to CREATE,
DROP or ALTER tables from ``$USER``. However, if you do so, please be aware
that you may have to temporarily GRANT those rights again when you update the
merchant backend. For details on how to REVOKE or GRANT these rights, consult
-the Postgres documentation.
-
-Commands, like ``taler-merchant-dbinit``, that support the ``-l LOGFILE``
-command-line option, send logging output to standard error by default.
-See :doc:`manpages/taler-merchant-dbinit.1` for more information.
+the PostgreSQL documentation.
.. include:: frags/db-stores-sensitive-data.rst
@@ -638,95 +610,47 @@ section, the following options need to be configured:
- The ``EXCHANGE_BASE_URL`` option specifies the exchange’s base URL.
For example, to use the Taler demonstrator, specify:
- .. code-block:: console
+ .. code-block:: ini
- $ taler-config -s MERCHANT-EXCHANGE-demo \
- -o EXCHANGE_BASE_URL \
- -V https://exchange.demo.taler.net/
+ [merchant-exchange-kudos]
+ EXCHANGE_BASE_URL = "https://exchange.demo.taler.net/"
- The ``MASTER_KEY`` option specifies the exchange’s master public key
in base32 encoding. For the Taler demonstrator, use:
- .. code-block:: console
+ .. code-block:: ini
+
+ [merchant-exchange-kudos]
+ MASTER_KEY = "GNRJCH0HYKN59939JC0CJ2JDC7ZNEBSATJFF00CVS3WPG4TQEA7G"
- $ taler-config -s MERCHANT-EXCHANGE-demo \
- -o MASTER_KEY \
- -V FH1Y8ZMHCTPQ0YFSZECDH8C9407JR3YN0MF1706PTG24Q4NEWGV0
+ You can find out this key by running ``curl https://exchange.demo.taler.net/keys | jq .master_public_key``.
- The ``CURRENCY`` option specifies the exchange’s currency.
For the Taler demonstrator, use:
- .. code-block:: console
-
- $ taler-config -s MERCHANT-EXCHANGE-demo \
- -o CURRENCY \
- -V KUDOS
-
-Note that multiple exchanges can be added to the system by using different
-tokens in place of ``demo`` in the examples above. Note that all of the
-exchanges must use the same currency: If the currency does not match the main
-currency from the ``TALER`` section, the exchange is ignored. If you need to
-support multiple currencies, you need to configure a backend per currency.
-
-.. note::
-
- Manually setting up exchanges is only recommended under special
- circumstances. In general, GNU Taler will include trustworthy
- auditors (for each currency) in the default configuration, and
- there is rarely a good reason for trusting an exchange without
- an accredited auditor.
-
-
+ .. code-block:: ini
-Auditor
-^^^^^^^
-
-To add an auditor to the list of trusted auditors (which implies
-that all exchanges audited by this auditor will be trusted!)
-you create a section with a name that starts with “MERCHANT-AUDITOR-”. In
-4that section, the following options need to be configured:
-
-- The ``AUDITOR_BASE_URL`` option specifies the auditor’s base URL.
- For example, to use the Taler demonstrator's auditor, specify:
-
- .. code-block:: console
-
- $ taler-config -s MERCHANT-AUDITOR-demo \
- -o AUDITOR_BASE_URL \
- -V https://exchange.demo.taler.net/
-
-- The ``AUDITOR_KEY`` option specifies the auditor's public key
- in base32 encoding. For the Taler demonstrator, use:
-
- .. code-block:: console
-
- $ taler-config -s MERCHANT-AUDITOR-demo \
- -o AUDITOR_KEY \
- -V DSDASDXAMDAARMNAD53ZA4AFAHA2QADAMAHHASWDAWXN84SDAA11
-
-- The ``CURRENCY`` option specifies the auditor’s currency.
- For the Taler demonstrator, use:
+ [merchant-exchange-kudos]
+ CURRENCY = "KUDOS"
- .. code-block:: console
-
- $ taler-config -s MERCHANT-AUDITOR-demo \
- -o CURRENCY \
- -V KUDOS
+Note that multiple exchanges can be added to the system by using different
+identifiers in place of ``KUDOS`` in the example above. Note that all of the
+exchanges actually used will use the same currency: If the currency does not
+match the main ``CURRENCY`` option from the ``taler`` section, the respective
+``merchant-exchange-`` section is automatically ignored. If you need support
+for multiple currencies, you need to deploy one backend per currency.
-Note that multiple auditors can be added to the system by using different
-tokens in place of ``demo`` in the examples above. Note that all of the
-auditors must use the same currency: If the currency does not match the main
-currency from the ``TALER`` section, the auditor is ignored. If you need to
-support multiple currencies, you need to configure a backend per currency.
+The merchant already ships with a default configuration that contains the
+``merchant-exchange-kudos`` section from above.
.. note::
- Manually adding auditors is only recommended under special
- circumstances. In general, GNU Taler will include trustworthy
- auditors (for each currency) in the default configuration, and
- there is rarely a good reason for adding an auditor that is
- not coordinating its activities with the Taler developers.
+ Manually setting up exchanges is only recommended under special
+ circumstances. In general, GNU Taler distributions will include trustworthy
+ exchanges (for each currency) in the default configuration, and there is
+ rarely a good reason for trusting an exchange that has no relationship
+ with the GNU Taler development team.
.. _Sample-backend-configuration:
@@ -740,41 +664,31 @@ The following is an example for a complete backend configuration:
.. code-block:: ini
- [TALER]
+ [taler]
CURRENCY = KUDOS
- [MERCHANT]
+ [merchant]
SERVE = TCP
PORT = 8888
DATABASE = postgres
- [MERCHANTDB-postgres]
- CONFIG = postgres:///donations
+ [merchantdb-postgres]
+ CONFIG = postgres:///taler-merchant
- [merchant-exchange-NAME]
+ [merchant-exchange-kudos]
EXCHANGE_BASE_URL = https://exchange.demo.taler.net/
MASTER_KEY = FH1Y8ZMHCTPQ0YFSZECDH8C9407JR3YN0MF1706PTG24Q4NEWGV0
- # If currency does not match [TALER] section, the exchange
+ # If currency does not match [taler] section, the exchange
# will be ignored!
CURRENCY = KUDOS
- [merchant-auditor-NAME]
- AUDITOR_BASE_URL = https://auditor.demo.taler.net/
- AUDITOR_KEY = DSDASDXAMDAARMNAD53ZA4AFAHA2QADAMAHHASWDAWXN84SDAA11
- # If currency does not match [TALER] section, the auditor
- # will be ignored!
- CURRENCY = KUDOS
-
-Given the above configuration, the backend will use a database named
-``donations`` within Postgres.
+Given the above configuration, the backend will use a PostgreSQL database
+named ``donations`` running on the same host.
The backend will deposit the coins it receives to the exchange at
https://exchange.demo.taler.net/, which has the master key
``FH1Y8ZMHCTPQ0YFSZECDH8C9407JR3YN0MF1706PTG24Q4NEWGV0``.
-Please note that ``doc/config.sh`` will walk you through all
-configuration steps, showing how to invoke ``taler-config`` for each of
-them.
.. _Launching-the-backend:
@@ -785,23 +699,29 @@ Launching the backend
.. index:: taler-merchant-httpd
Assuming you have configured everything correctly, you can launch the
-merchant backend as ``$USER`` using
+merchant backend as ``$USER`` using (to provide a trivial example):
.. code-block:: console
- $ taler-merchant-httpd
+ $ taler-merchant-httpd &
+ $ taler-merchant-webhook &
+ $ taler-merchant-wirewatch &
+ $ taler-merchant-depositcheck &
+ $ taler-merchant-exchange &
-To ensure the process runs always in the background and also after rebooting,
-you should use systemd, cron or some other init system of your operating
-system to launch the process. Consult the documentation of your operating
-system for how to start and stop daemons.
+To ensure these processes run always in the background and also after
+rebooting, you should use systemd, cron or some other init system of your
+operating system to launch the process. You should also periodically re-start
+these services to prevent them from exhausing the memory utilization of the
+PostgreSQL database. Consult the documentation of your operating system for
+how to start and stop daemons.
.. note::
When using the Debian/Ubuntu packages, the systemd configuration
will already exist. You only need to enable and start the service
- using ``systemctl enable taler-merchant-httpd`` and
- ``systemctl start taler-merchant-httpd``. Additionally, you should
+ using ``systemctl enable taler-merchant.target`` and
+ ``systemctl start taler-merchant.target``. Additionally, you should
review the ``/etc/apache2/sites-available/taler-merchant.conf``
or ``/etc/nginx/sites-available/taler-merchant`` (these files
contain additional instructions to follow), symlink it to
@@ -809,18 +729,18 @@ system for how to start and stop daemons.
should be able to visit the merchant backend at the respective
HTTP(S) endpoint.
-
If everything worked as expected, the command
.. code-block:: console
- $ curl http://localhost:8888/config
+ $ wget -O - http://localhost:8888/config
should return some basic configuration status data about the service.
-Please note that your backend is right now likely globally reachable. You can either:
+Please note that your backend might then be globally reachable without
+any access control. You can either:
- * Use the ``--auth=$TOKEN`` command-line option to set an access token to be provided in an ``Authorize: Bearer $TOKEN`` HTTP header. Note that this can be used at anytime to override access control, but remains only in effect until a first instance is created or an existing instance authentication setting is modified.
+ * Use the ``--auth=$TOKEN`` command-line option to **taler-merchant-httpd** to set an access token to be provided in an ``Authorize: Bearer $TOKEN`` HTTP header. Note that this can be used at anytime to override access control, but remains only in effect until a first instance is created or an existing instance authentication setting is modified.
* Set the ``TALER_MERCHANT_TOKEN`` environment variable to ``$TOKEN`` for the same effect. This method has the advantage of ``$TOKEN`` not being visible as a command-line interface to other local users on the same machine.
* Set up an instance with an authentication token before some unauthorized person has a chance to access the backend. As the backend is useless without any instance and the chances of remote attackers during the initial configuration is low, this is probably sufficient for most use-cases. Still, keep the first two scenarios in mind in case you ever forget your access token!
@@ -831,98 +751,90 @@ and use TLS for improved network privacy, see :ref:`Secure setup <Secure-setup>`
.. index:: instance
.. _Instance-setup:
+
Instance setup
==============
-First of all, we recommend the use of the single-page administration
-application that is served by default at the base URL of the merchant backend.
-You can use it to perform all steps described in this section (and more!),
-using a simple Web interface instead of the ``curl`` commands given below.
+We recommend the use of the single-page administration application (SPA) that
+is served by default at the base URL of the merchant backend. You can use it
+to perform all steps described in this section (and more!), using a simple Web
+interface. Alternatively, you can also use the ``wget`` commands given below.
-The first step for using the backend involves the creation of a ``default``
-instance. The ``default`` instance can also create / delete / configure other
-instances, similar to the ``root`` account on UNIX. When no instance exists
-and ``taler-merchant-httpd`` was started without the ``--auth`` option, then
-the backend is reachable without any access control (unless you configured
-some in the reverse proxy).
+Regardless of which approach you use, the first step for using the backend
+involves the creation of a ``default`` instance. The ``default`` instance can
+also create, configure or delete other instances, similar to the ``root``
+account on UNIX. When no instance exists and ``taler-merchant-httpd`` was
+started without the ``--auth`` option, then the backend is reachable without
+any access control (unless you configured some in the reverse proxy).
The following documentation shows how to handle any instance. Thus, if you
want to have multiple instances, you may need to perform the steps multiple
times, once for each instance.
.. note::
- A security concern is that normal API usage leaks instance existence.
+
+ A potential security concern is that normal API usage leaks instance existence.
This means unauthorized users can distinguish between the case where the
instance does not exist (HTTP 404) and the case where access is denied
(HTTP 403).
- This is all moot behind a properly configured
+ This is concern can be addressed using a properly configured
:ref:`reverse proxy <reverse-proxy-configuration>`.
-KUDOS Accounts
---------------
+Instance setup with the SPA
+---------------------------
-The main configuration data that must be provided for each instance
-is the bank account information.
+In order to setup an instance, you need the merchant backend to already be
+running, and you must either have the credentials for the "default" instance,
+or no instance must be configured at all yet.
-In order to receive payments, the merchant backend needs to
-communicate bank account details to the exchange.
+To start, point your browser to ``$PROTO://backend.$DOMAIN_NAME/``, replacing
+"$PROTO" with "https" or (rarely) "http" and "$DOMAIN_NAME" with your
+organizations DNS domain or subdomain.
-The bank account information is provided in the form of a ``payto://``-URI.
-See `RFC 8905 <https://tools.ietf.org/html/rfc8905>`_
-for the format of ``payto://``-URIs.
+.. note::
-For first tests, you should sign up for a KUDOS bank
-account at `https://bank.demo.taler.net/ <https://bank.demo.taler.net/>`_.
-In this case, the ``payto://``-URI will be of the form
-``payto://x-taler-bank/bank.demo.taler.net/$USERNAME`` where ``$USERNAME``
-must be replaced with the name of the account that was established
-at `https://bank.demo.taler.net/ <https://bank.demo.taler.net/>`_.
+ The label "backend" here is also just a suggestion, your administrator
+ can in principle choose any name.
+You should be welcomed by the following merchant backoffice page:
-IBAN Accounts
--------------
+.. image:: screenshots/merchant_first_login.png
-When deploying Taler with the real banking system, you primarily need to
-change the currency of the configuration from KUDOS to the actual currency
-(such as EUR, USD, CHF) and provide a ``payto://``-URI of your real bank
-account. In Europe, this will involve knowing your IBAN number. If you have an
-IBAN, the corresponding ``payto://``-URI is simply ``payto://iban/$IBAN`` where
-``$IBAN`` must be replaced with the actual IBAN number.
+After supplying the required fields, primarily the name of your organization
+and the desired access token, click ``confirm``. You can change the instance
+settings later via the ``Settings`` entry in the menu on the left.
-Setup
-------
+Instance setup without the Web interface
+----------------------------------------
-With the knowledge of the ``payto://``-URI, instances can be configured by POSTing
-a request to ``/management/instances``. To create a first instance,
-create a file ``instance.json`` with an `InstanceConfigurationMessage`
+Instances can be created by POSTing a request to ``/management/instances``
+without using the Web interface. This could be useful if you want to create
+many instances programmatically. To create an instance without the Web
+interface create a file ``instance.json`` with an
+`InstanceConfigurationMessage`:
.. code-block:: json
{
- "payto_uris" : [ "$PAYTO_URI" ],
"id" : "default",
- "name": "example.com",
+ "name": "Example Inc.",
"address": { "country" : "zz" },
"auth": { "method" : "external"} ,
"jurisdiction": { "country" : "zz" },
- "default_max_wire_fee": "KUDOS:1",
- "default_wire_fee_amortization": 100,
- "default_max_deposit_fee": "KUDOS:1",
+ "use_stefan": true,
"default_wire_transfer_delay": { "d_ms" : 1209600000 },
"default_pay_delay": { "d_ms" : 1209600000 }
}
-In the text above, you must replace ``$PAYTO_URI`` with your actual
-``payto://``-URI. Also, be sure to replace ``KUDOS`` with the fiat currency if the
-setup is for an actual bank. The ``name`` field will be shown as the name of
-your shop. The ``address`` field is expected to contain your shop's physical
-address. The various defaults specify defaults for transaction fees your shop
-is willing to cover, how long offers made to the customer are valid, and how
-long the exchange has before it must wire the funds to your bank
-account. Those defaults can be modified for individual orders.
-For details, see the :ref:`contract terms <contract-terms>` specification.
+The ``name`` field will be shown as the name of your shop. The
+``address`` field is expected to contain your shop's physical address. The
+various defaults specify defaults for transaction fees your shop is willing to
+cover, how long offers made to the customer are valid, and how long the
+exchange has before it must wire the funds to your bank account. Those
+defaults can be modified for individual orders. For details, see the
+:ref:`contract terms <contract-terms>` specification.
You can then create the instance using:
@@ -938,6 +850,125 @@ Endpoints to modify (reconfigure), permanently disable (while keeping the data)
or purge (deleting all associated data) instances exist as well and are documented
in the :ref:`Merchant Backend API documentation <merchant-api>`.
+.. _instance-account-setup:
+
+Instance account setup
+======================
+
+Before you can use an instance productively, you need to configure one or more
+bank accounts. These bank accounts will be provided to the Taler exchange
+operator to tell it where to wire the income from your sales. Every bank
+account has an associated *wire method* which determines how an exchange can
+transfer the funds. The most commonly supported wire method is *iban*, which
+implies that bank accounts are identified by IBAN numbers and wire transfers
+are to be executed between IBAN accounts. For regional currency setups, the
+wire method could also be *x-taler-bank*.
+
+.. note::
+
+ When using a regional currency, you need to first create a bank account at
+ the regional bank. You may need to contact the respective administrator who
+ can set one up. After being able to login to the new bank account, you can
+ see your bank account number by clicking on the ``Welcome, $USERNAME``
+ message in the profile page. Next to the bank account number, you can find
+ a convenient button to copy the number to the clipboard.
+
+Not every exchange will support every *wire method*, and if you do not add a
+bank account with a wire method that is supported by a particular exchange,
+then you will not be able to receive payments via that exchange even if you
+configured the merchant backend to trust that exchange.
+
+The simplest way to configure an account is to use the Web interface which has
+specific forms for different wire methods. First, select ``Bank account`` at
+the left of the page. The following page should be shown:
+
+.. image:: screenshots/no_default_account_yet.png
+
+Click on the blue "+" sign on the top right of the page to add a new
+bank account. The following page should appear:
+
+.. image:: screenshots/enter_instance_details.png
+
+First, you should select the wire method, after which the dialog will show you
+additional fields specific to the wire method. For example, if youchoose
+``iban`` as the account type, the following page should appear:
+
+.. image:: screenshots/instance_iban_config.png
+
+Specifying the revenue gateway with username and password is optional and
+discussed in section :ref:`automatic-settlement-data-import` below.
+
+After providing the details and confirming, the shop is ready to generate orders
+and accept payments.
+
+
+
+Detecting Settlement: Manually Adding Transfers
+-----------------------------------------------
+
+The exchange may aggregate many small amounts into one larger wire transfer.
+If you want to safely determine for which orders have been settled (final
+payment from the exchange has been received), the backend must learn about the
+wire transfers made into your bank account. Basically, as a secure system, we
+do not simply trust a claim by the exchange that it would transfer the money,
+but we allow each merchant to check settlements.
+
+An easy (but somewhat tedious) way to check settlements is to manually add
+every wire transfer that a merchant bank account has received from the
+exchange with the total amount and the wire transfer subject. Given this
+information, the merchant backend will inquire with the exchange which
+individual payments were aggregated, check that the total amount is correct,
+and will then flag the respective contracts as wired.
+
+You can manually enter wire transfers under ``Transfers``. However, this is
+tedious, and so if your banking setup supports it, we highly recommend
+using the automatic settlement data import.
+
+.. _automatic-settlement-data-import:
+
+Automatic Settlement Data Import
+--------------------------------
+
+To automatically import settlement data, you need to provide the merchant
+backend with the address and access credentials of a
+:ref:`taler-bank-merchant-http-api` for each bank account of an instance. The
+revenue API endpoint will allow the merchant backend to obtain a list of all
+incoming wire transfers into your bank account and automatically import them
+into the list of confirmed wire transfers.
+
+Note that setting up a revenue API endpoint will usually require you to first
+ask your bank for EBICS access and to set up :ref:`libeufin-nexus` to provide
+the revenue API endpoint. The :ref:`libeufin-bank` used by regional currency
+setups also provides a revenue API endpoint at
+``$BANK_URL/accounts/$ACCOUNT_NAME/taler-revenue/``. Thus, when using a
+regional currency setup, simply use the ``$BANK_URL`` of your bank and specify
+your bank login name and password in the :ref:`instance-account-setup` dialog.
+
+
+Manually creating an order using the SPA
+========================================
+
+Click on ``Orders`` at the top left corner of the merchant backoffice page; the
+following page should appear
+
+.. image:: screenshots/create_orders.png
+
+After having filled the required fields, the interface should show the
+following page with the related links to check the status of the order and let
+wallets pay for it.
+
+.. image:: screenshots/payment_links.png
+
+In order to test the setup, it should be now possible to use the command line wallet
+to withdraw Taler coins and spend them to pay for the order we just created.
+
+In practice, you will rarely if ever setup orders manually like this. Instead,
+a `GNU Taler e-commerce front-end
+<https://taler.net/en/docs.html#extensions>`_ or the
+:ref:`taler-merchant-pos-app` will do this on-demand. Here, you will only need
+to provide the respective front-ends with the URL of your instance
+(e.g. ``https://backend.$DOMAIN/instances/$NAME``) and your access token.
+
.. _Secure-setup:
@@ -947,11 +978,12 @@ Secure setup
.. index:: security
.. index:: TLS
-The Taler backend does not include even the most basic forms of
-access control or transport layer security. Thus, production
-setups **must** deploy the Taler backend behind an HTTP(S) server
-that acts as a *reverse proxy*, performs TLS termination and
-authentication and then forwards requests to the backend.
+The Taler backend is deliberately simple in terms of support for access
+control or transport layer security (TLS). Thus, production setups **must**
+deploy the Taler backend behind an HTTP(S) server that acts as a *reverse
+proxy*, performs TLS termination and authentication and then forwards requests
+to the backend.
+
Using UNIX domain sockets
-------------------------
@@ -959,10 +991,11 @@ Using UNIX domain sockets
To ensure that the merchant backend is not exposed directly to the network,
you *should* bind the backend to a UNIX domain socket:
-.. code-block:: console
+.. code-block:: ini
- $ taler-config -s MERCHANT -o SERVE -V UNIX
- $ taler-config -s MERCHANT -o UNIXPATH -V /some/path/here.sock
+ [MERCHANT]
+ SERVE = unix
+ UNIXPATH = "/some/path/here.sock"
Do not use a UNIX domain socket path in "/tmp": systemd (or other init
systems) may give Web servers a private "/tmp" thereby hiding UNIX domain
@@ -970,8 +1003,9 @@ sockets created by other users/processes in "/tmp".
If UNIX domain sockets are for some reason not possible, you *may* use a
host-based firewall to block access to the TCP port of the merchant backend,
-but this is *not recommended*. Relying on NAT or network firewalls for access
-control is gross negligence.
+but this is *not recommended*. If you do need a TCP socket, you should
+instead strongly consider using the "BIND_TO" option to at least bind it only
+to "localhost".
.. _reverse-proxy-configuration:
@@ -1022,195 +1056,135 @@ Note that the above again assumes your domain name is ``example.com`` and that
you have TLS configured. Note that you must add the ``https`` header unless
your site is not available via TLS.
-The above configurations are both incomplete. You must still additionally
-set up access control!
-
Access control
--------------
All endpoints with ``/private/`` in the URL must be restricted to authorized
users of the respective instance. Specifically, the HTTP server must be
-configured to only allow access to ``$BASE_URL/private/`` and
-``$BASE_URL/management/`` to the authorized users of the default instance, and
-to ``$BASE_URL/instances/$ID/private/`` to the authorized users of the instance
-``$ID``.
+configured to only allow access to ``$BASE_URL/private/`` to the authorized
+users of the default instance, and to ``$BASE_URL/instances/$ID/private/`` to
+the authorized users of the instance ``$ID``.
-How access control is done (TLS client authentication, HTTP basic or digest
-authentication, etc.) is completely up to the merchant and does not matter to
-the Taler merchant backend.
+By default, the GNU Taler merchant backend simply requires the respective
+HTTP requests to include an "Authorization" header with a "Bearer" token
+set to the respective shared secret which must begin with "secret-token:"
+(following RFC 8959).
-Note that all of the other endpoints (without ``/private/`` or ``/management/``)
+Note that all of the other endpoints (without ``/private/``)
are expected to be fully exposed to the Internet, and wallets may have to
interact with those endpoints directly without client authentication.
-Nginx
-^^^^^
-For Nginx, you can implement token-based merchant backend authentication as
-follows:
+Status code remapping
+---------------------
-.. code-block:: nginx
+Normal API usage leaks instance existence information. Distinguishing between
+404 (Not found) and 403 (Forbidden) is useful for diagnostics.
- location ~ /private/ {
- if ($http_authorization !~ "(?i)ApiKey SECURITYTOKEN") {
- return 401;
- }
- proxy_pass ...; // as above
- }
- location /management/ {
- if ($http_authorization !~ "(?i)ApiKey SECURITYTOKEN") {
- return 401;
- }
- proxy_pass ...; // as above
- }
-
-Here, ``SECURITYTOKEN`` should be replaced with the actual shared secret. Note
-that the ``~`` ensures that the above matches all endpoints that include the
-string ``/private/``. If you only run a single instance, you could simply
-specify ``/private/`` without the ``~`` to only configure the access policy for
-the default instance.
-
-If you are running different instances on the same backend, you
-likely will want to specify different access control tokens for
-each instance:
+For higher security (by leaking less information), you can add the following
+fragment, which remaps all 404 response codes to 403.
+
+Nginx
+^^^^^
.. code-block:: nginx
- location ~ ^/instances/foo/private/ {
- if ($http_authorization !~ "(?i)ApiKey FOOTOKEN") {
- return 401;
- }
- proxy_pass ...; # as above
- }
- location ~ ^/instances/bar/private/ {
- if ($http_authorization !~ "(?i)ApiKey BARTOKEN") {
- return 401;
- }
- proxy_pass ...; # as above
- }
- location /private/ {
- if ($http_authorization !~ "(?i)ApiKey MASTERTOKEN") {
- return 401;
- }
- proxy_pass ...; # as above
- }
- location /management/ {
- if ($http_authorization !~ "(?i)ApiKey MASTERTOKEN") {
- return 401;
- }
- proxy_pass ...; # as above
- }
- location ~ /private/ {
- return 401; # access to instances not explicitly configured is forbidden
- }
+ error_page 404 =403 /empty.gif;
Apache
^^^^^^
-For Apache, you should first enable ``mod_rewrite``:
+.. code-block:: apacheconf
-.. code-block:: console
+ cond %{STATUS} =404
+ set-status 403
- $ a2enmod rewrite
-Then, you can restrict to an access control token using:
+Customization
+=============
-.. code-block:: apacheconf
+Legal conditions for using the service
+--------------------------------------
- <Location "/">
- RewriteEngine On
- RewriteCond "%{HTTP:AUTHORIZATION}" "!=SECURITYTOKEN"
- RewriteRule "(.+)/private/" "-" [F]
- RewriteRule "/management/" "-" [F]
+.. include:: frags/legal.rst
- ProxyPass "unix:/some/path/here.sock|http://example.com/"
- </Location>
+.. _MerchantTemplateCustomization:
-Here, ``SECURITYTOKEN`` should be replaced with the actual shared secret. Note
-that the ``(.+)`` ensures that the above matches all endpoints that include the
-string ``/private/``. If you only run a single instance, you could simply
-specify ``/private/`` without the ``(.+)`` to only configure the access policy for
-the default instance.
+Template Customization
+----------------------
-If you are running different instances on the same backend, you
-likely will want to specify different access control tokens for
-each instance:
+The installation process will install various HTML templates to be served to
+trigger the wallet interaction. You may change those templates to your own
+design. The templating language used is `C implementation of mustache
+<https://gitlab.com/jobol/mustach>`__, and the templates are in the
+``share/taler/merchant/templates/`` directory.
-.. code-block:: apacheconf
+The file names must be of the form ``$NAME.$LANG.must`` where ``$NAME`` is the
+name of the template and ``$LANG`` is the 2-letter language code of the
+template. English templates must exist and will be used as a fallback. If the
+browser (user-agent) has provided language preferences in the HTTP header and
+the respective language exists, the correct language will be automatically
+served.
- <Location "/instances/foo/">
- RewriteEngine On
- RewriteCond "%{HTTP:AUTHORIZATION}" "!=FOOTOKEN"
- RewriteRule "/instances/foo/private/" "-" [F]
+The following subsections give details about each of the templates. The
+subsection titles are the ``$NAME`` of the respective template.
- ProxyPass ... # as above
- </Location>
+request_payment
+^^^^^^^^^^^^^^^
- <Location "/instances/bar/">
- RewriteEngine On
- RewriteCond "%{HTTP:AUTHORIZATION}" "!=BARTOKEN"
- RewriteRule "/instances/bar/private/" "-" [F]
+Page shown to request the user to make a payment.
- ProxyPass ... # as above
- </Location>
+This template is instantiated using the following information:
- <Location "/">
- RewriteEngine On
- RewriteCond "%{HTTP:AUTHORIZATION}" "!=MASTERTOKEN"
- RewriteRule "/private/" "-" [F]
- RewriteRule "/management/" "-" [F]
- RewriteRule "(.+)/private/" "-" [F] # reject all others
+ * taler_pay_uri: String; the ``taler://pay/`` URI that must be given
+ to the wallet to initiate the payment
- ProxyPass ... # as above
- </Location>
+ * taler_pay_qrcode_svg: Image; an SVG image of the QR code with the
+ ``taler_pay_uri``.
-Please note that these are simply examples of how one could use Nginx or
-Apache2 for access control. Both HTTP servers support many other forms of
-authentication, including TLS client certificates, HTTP basic and digest
-authentication and others, which can all be used (possibly in combination) to
-restrict access to the internal API to authorized clients.
+ * order_summary: String; a text summarizing the order
-System administrators are strongly advised to test their access control
-setup before going into production!
+ * order_status_url: URL of the merchant backend where the order status
+ can be found, useful for long-polling to check if the order has been paid
-Status code remapping
----------------------
-Normal API usage leaks instance existence information.
-Distinguishing between 404 (Not found) and 403 (Forbidden)
-is useful for diagnostics.
+offer_refund
+^^^^^^^^^^^^
-For higher security (by leaking less information),
-you can add the following fragment,
-which remaps all 404 response codes to 403.
+Page shown to offer a customer a refund.
-Nginx
-^^^^^
+This template is instantiated using the following information:
-.. code-block:: nginx
+ * taler_refund_uri: String; the ``taler://pay/`` URI that must be given
+ to the wallet to initiate the payment
- error_page 404 =403 /empty.gif;
+ * taler_refund_qrcode_svg: Image; an SVG image of the QR code with the
+ ``taler_pay_uri``.
-Apache
-^^^^^^
+ * refund_amount: Amount; how much did the merchant refund
-.. code-block:: apacheconf
+ * refund_taken: Amount; how much did the customer already take back in refunds
- cond %{STATUS} =404
- set-status 403
+ * order_summary: String; a text summarizing the order
-Customization
-=============
-Templates
----------
+show_order_details
+^^^^^^^^^^^^^^^^^^
+
+Page shown to the user when they go back to the payment page but
+no payment is required and no refund is present.
+
+This template is instantiated using the following information:
+
+ * order_summary: String; a text summarizing the order
-The installation process will install various HTML templates to be served
-to trigger the wallet interaction. You may change those templates to your
-own design. The templating language used is Mustach, and the templates
-are in the ``share/taler/merchant/templates/`` directory.
+ * contract_terms: Object; the full contract terms (shoud probably
+ not be shown in full!)
+ * refund_amount: Amount; how much did the merchant refund
+
+ * refund_taken: Amount; how much did the customer already take back in refunds
Static files
------------
@@ -1241,7 +1215,8 @@ Limitations
All of the static files must fit into memory and it must be possible for the
process to hold open file handles for all of these files. You may want
to increase the ``ulimit`` of the ``taler-merchant-httpd`` process if you have
-templates for many languages.
+many static files. Note that Mustach templates do not increase the number of
+open files.
The backend determines the MIME type based on the file's extension. The list
of supported extensions is hard-coded and includes common text and image
@@ -1256,8 +1231,8 @@ features.
Upgrade procedure
=================
-This is the general upgrade procedure. Please see the release notes
-for your specific version to check if a particular release has special
+This section describes the general upgrade procedure. Please see the release
+notes for your specific version to check if a particular release has special
upgrade requirements.
Please note that upgrades are ONLY supported for released version of the
@@ -1265,8 +1240,8 @@ merchant. Attempting to upgrade from or to a version in Git is not supported
and may result in subtle data loss.
To safely upgrade the merchant, you should first stop the existing
-``taler-merchant-httpd`` process, backup your merchant database (see Postgres
-manual), and then install the latest version of the code.
+``taler-merchant-httpd`` process, backup your merchant database (see
+PostgreSQL manual), and then install the latest version of the code.
If you REVOKED database permissions, ensure that the rights to CREATE,
DROP, and ALTER tables are GRANTed to ``$USER`` again. Then, run:
@@ -1276,125 +1251,21 @@ DROP, and ALTER tables are GRANTed to ``$USER`` again. Then, run:
$ taler-merchant-dbinit
to upgrade the database to the latest schema. After that, you may again
-REVOKE the database permissions. Finally, restart the HTTP service, either via
-your systemd or init system, or directly using:
-
-.. code-block:: console
-
- $ taler-merchant-httpd
-
-
-.. _Tipping-visitors:
-
-Tipping visitors
-================
-
-.. index:: tipping
-
-Taler can also be used to tip Web site visitors. For example, you may be
-running an online survey, and you want to reward those people that have
-dutifully completed the survey. If they have installed a Taler wallet,
-you can provide them with a tip for their deeds. This section describes
-how to setup the Taler merchant backend for tipping.
-
-There are three basic steps that must happen to tip a visitor.
-
-.. _Fund-the-reserve:
-
-Fund the reserve
-----------------
-
-.. index:: reserve
-
-First, the reserve must be setup in the merchant backend. A reserve
-is always tied to a particular instance. To create a reserve with
-10 KUDOS at instance ``default`` using the demo exchange, use:
-
-.. code-block:: console
-
- $ taler-merchant-setup-reserve \
- -a KUDOS:10 \
- -e https://exchange.demo.taler.net/ \
- -m http://localhost:8888/instances/default
-
-The above command assumes that the merchant runs on localhost on
-port 8888.
-For more information, including how to transmit authentication information
-to the backend, see :doc:`manpages/taler-merchant-setup-reserve.1`.
-
-The command will output a ``payto://`` URI which specifies where to
-wire the funds and which wire transfer subject to use.
-
-FIXME: add full example output.
-
-In our example, the output for the wire transfer subject is:
-
-.. code-block:: none
-
- QPE24X8PBX3BZ6E7GQ5VAVHV32FWTTCADR0TRQ183MSSJD2CHNEG
-
-You now need to make a wire transfer to the exchange’s bank account
-using the given wire transfer subject.
-
-Make your wire transfer and (optionally) check at
-“https://exchange/reserves/QPE24X...” whether your transfer has arrived at the
-exchange.
-
-Once the funds have arrived, you can start to use the reserve for
-tipping.
-
-Note that an exchange will typically close a reserve after four weeks, wiring
-all remaining funds back to the sender’s account. Thus, you should plan to
-wire funds corresponding to a campaign of about two weeks to the exchange
-initially. If your campaign runs longer, you should setup another reserve
-every other week to ensure one is always ready.
-
-.. _Authorize-a-tip:
-
-Authorize a tip
----------------
-
-When your frontend has reached the point where a client is supposed to receive
-a tip, it needs to first authorize the tip. For this, the frontend must use
-a POST to ``/private/reserves/$RESERVE_PUB/authorize-tip``. To authorize a
-tip, the frontend has to provide the following information in the body of the
-POST request:
+REVOKE the database permissions. Finally, restart the merchant services
+processes, either via your systemd or init system, or directly.
-- The amount of the tip
-- The justification (only used internally for the back-office)
-- The URL where the wallet should navigate next after the tip was
- processed
-
-- The tip-pickup URL (see next section)
-
-In response to this request, the backend will return a tip token, an
-expiration time and the exchange URL. The expiration time will indicate
-how long the tip is valid (when the reserve expires). The tip token is
-an opaque string that contains all the information needed by the wallet
-to process the tip. The frontend must send this tip token to the browser
-in a special “402 Payment Required” response inside the ``X-Taler-Tip``
-header.
-
-The frontend should handle errors returned by the backend, such as
-misconfigured instances or a lack of remaining funds for tipping.
-
-.. _Picking-up-of-the-tip:
-
-Picking up of the tip
----------------------
-
-The wallet will POST a JSON object to the shop’s
-``/tips/$TIP_ID/pickup`` handler.
-The frontend must then forward this request to the backend. The response
-generated by the backend can then be forwarded directly to the wallet.
+Advanced topics
+===============
+taler-config
+------------
+.. index:: taler-config
-Advanced topics
-===============
+.. include:: frags/using-taler-config.rst
.. _MerchantDatabaseScheme:
@@ -1410,159 +1281,47 @@ allowing administrators to purge records that are no longer required.
The database scheme used by the merchant looks as follows:
-.. image:: merchant-db.png
-
-
-
-Configuration format
---------------------
-
-.. index:: configuration
-
-In Taler realm, any component obeys to the same pattern to get
-configuration values. According to this pattern, once the component has
-been installed, the installation deploys default values in
-``${prefix}/share/taler/config.d/``, in ``.conf`` files. In order to override
-these defaults, the user can write a custom .conf file and either pass
-it to the component at execution time, or name it ``taler.conf`` and place
-it under ``$HOME/.config/``.
-
-A config file is a text file containing sections, and each section
-contains its values. The right format follows:
-
-.. code-block:: ini
-
- [section1]
- value1 = string
- value2 = 23
-
- [section2]
- value21 = string
- value22 = /path22
-
-Throughout any configuration file, it is possible to use ``$``-prefixed
-variables, like ``$VAR``, especially when they represent filesystem
-paths. It is also possible to provide defaults values for those
-variables that are unset, by using the following syntax:
-``${VAR:-default}``. However, there are two ways a user can set
-``$``-prefixable variables:
-
-by defining them under a ``[paths]`` section, see example below,
-
-.. code-block:: ini
-
- [paths]
- TALER_DEPLOYMENT_SHARED = ${HOME}/shared-data
- ...
- [section-x]
- path-x = ${TALER_DEPLOYMENT_SHARED}/x
-
-or by setting them in the environment:
-
-.. code-block:: console
-
- $ export VAR=/x
-
-The configuration loader will give precedence to variables set under
-``[path]``, though.
-
-The utility ``taler-config``, which gets installed along with the
-exchange, serves to get and set configuration values without directly
-editing the ``.conf``. The option ``-f`` is particularly useful to resolve
-pathnames, when they use several levels of ``$``-expanded variables. See
-``taler-config --help``.
-
-Note that, in this stage of development, the file
-``$HOME/.config/taler.conf`` can contain sections for *all* the
-components. For example, both an exchange and a bank can read values from
-it.
-
-The `deployment repository <https://git.taler.net/deployment>`_ contains examples of
-configuration file used in our demos. See under ``deployment/config``.
-
- **Note**
-
- Expectably, some components will not work just by using default
- values, as their work is often interdependent. For example, a
- merchant needs to know an exchange URL, or a database name.
-
-.. _Using-taler_002dconfig:
+.. image:: images/merchant-db.png
-Using taler-config
-^^^^^^^^^^^^^^^^^^
-
-.. index:: taler-config
-
-The tool ``taler-config`` can be used to extract or manipulate
-configuration values; however, the configuration use the well-known INI
-file format and can also be edited by hand.
-
-Run:
-
-.. code-block:: console
-
- $ taler-config -s $SECTION
-
-to list all of the configuration values in section ``$SECTION``.
+.. _MerchantBenchmarking:
-Run:
+Benchmarking
+------------
-.. code-block:: console
+The merchant codebase offers the ``taler-merchant-benchmark`` tool to populate
+the database with fake payments. The main goal of the benchmarking tool is to
+serve as a starting point (!) for merchants that are interested in developing
+stress tests to see how far their infrastructure can scale. As is, it
+currently is not actually good at stressing the payment system.
- $ taler-config -s $section -o $option
+The ``taler-unified-setup.sh`` script can be used to launch all required
+services and clients. However, the resulting deployment is simplistic
+(everything on the local machine, one single-threaded process per service
+type) and not optimized for performance at all. However, this can still be
+useful to assess the performance impact of changes
+to the code or configuration.
-to extract the respective configuration value for option ``$option`` in
-section ``$section``.
-Finally, to change a setting, run:
+Various configuration files that can be used in the code snippets in this
+section can be found in the ``src/merchant-tools/`` directory of the
+merchant. These are generally intended as starting points. Note that the
+configuration files ending in ``.edited`` are created by
+``taler-unified-setup.sh`` and contain some options that are determined at
+runtime by the setup logic provided by ``taler-unified-setup.sh``.
-.. code-block:: console
+See :ref:`Taler Exchange Manual <Benchmark-choose-bank>` for how to use ``taler-unified-setup.sh`` to setup the system and in particular on how to specify the bank to be used.
- $ taler-config -s $section -o $option -V $value
-to set the respective configuration value to ``$value``. Note that you
-have to manually restart the Taler backend after you change the
-configuration to make the new configuration go into effect.
+Running taler-merchant-benchmark
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Some default options will use ``$``-variables, such as ``$DATADIR`` within
-their value. To expand the ``$DATADIR`` or other ``$``-variables in the
-configuration, pass the ``-f`` option to ``taler-config``. For example,
-compare:
+You can run the tool as follows:
.. code-block:: console
- $ taler-config -s PATHS \
- -o TALER_DATA_HOME
- $ taler-config -f -s PATHS \
- -o TALER_DATA_HOME
-
-While the configuration file is typically located at
-``$HOME/.config/taler.conf``, an alternative location can be specified
-to ``taler-merchant-httpd`` and ``taler-config`` using the ``-c``
-option.
-
-
-
-Advanced experimental features
-==============================
-
-This section describes features that most merchants will not
-need, or will not need initially.
-
-.. _MerchantBenchmarking:
-
-Benchmarking
-------------
-
-The merchant codebase offers the ``taler-merchant-benchmark`` tool to
-populate the database with fake payments. This tool is in charge of
-starting a merchant, exchange, and bank processes, and provides them all
-the input to accomplish payments. Note that each component will use its
-own configuration (as they would do in production).
-
-The main goal of the benchmarking tool is to serve as a starting point (!) for
-merchants that are interested in developing stress tests to see how far their
-infrastructure can scale.
+ $ CONF=benchmark-rsa.conf
+ $ taler-unified-setup.sh -emwt -c "$CONF" -f -u exchange-account-1
+ $ time taler-merchant-benchmark ordinary -c "$CONF".edited -u exchange-account-1 -f -p 20
The current tool has already a few options, but we expect that to deliver
*relevant* results it will need to be customized to better reflect the
@@ -1571,47 +1330,16 @@ likely involve writing (C) code. We welcome contributions to make it easier
to customize the benchmark and/or to cover more realistic workloads from the
start.
-
-Benchmark setup
----------------
-
-The ``taler-merchant-benchmark`` tool will automatically launch and configure the
-exchange, (Python) bank and other tools required for the benchmark. However,
-the configuration file must be provided and have consistent options set. The
-options that require special care include the exchange's public key (which
-must match the private key in the file specified by the configuration), the
-currency (which must be consistent across the file), the denomination
-structure (which must enable payments in the range of 100ths of the unit
-currency (often called cents)). Furthermore, the benchmark will set the
-Exchange bank account password to be "x", so the configuration must also
-specify "x" for the passphrase. Finally, the bank must be configured to allow
-for substantial debt least the transactions by the benchmark run out of
-digital cash.
-
-A relatively minimal configuration could look like this:
-
-.. literalinclude:: merchant-benchmark.conf
-
-
-Note that the public key must match the exchange's
-private key and that the Postgres database must
-exist before launching the benchmark. You also
-will need to ensure that the Exchange's
-details are set up.
-For details, see the :ref:`Exchange Operator Manual <Bank-account>`.
-
-
-Running the benchmark command
------------------------------
-
The tool takes all of the values it needs from the command line, with
-one of them being mandatory:
+some of them being common to all subcommands:
-- ``--exchange-account=SECTION`` Specifies which configuration
+- ``--exchange-account-section=SECTION`` Specifies which configuration
section specifies the bank account for the exchange that
should be used for the benchmark. For the example
configuration above, the SECTION value provided must be
``exchange-account-exchange``.
+- ``--fakebank`` Specifies that the benchmark should expect to interact
+ with a fakebank (instead of libeufin).
The tool comes with two operation modes: *ordinary*, and *corner*.
The first just executes normal payments, meaning that it uses the
@@ -1620,8 +1348,10 @@ second gives the chance to leave some payments unaggregated, and also to
use merchant instances other than the default (which is, actually, the
one used by default by the tool).
-Note: the ability of driving the aggregation policy is useful for testing
-the back-office facility.
+.. note::
+
+ The ability to drive the aggregation policy is useful for testing
+ the back-office facility.
Any subcommand is also equipped with the canonical ``--help`` option, so
feel free to issue the following command in order to explore all the
@@ -1642,19 +1372,10 @@ interesting, there are:
perform *UN* (one coin) payments that will be left unaggregated.
As for the ``ordinary`` subcommand, it is worth explaining the following
-options:
+option:
- ``--payments-number=PN`` Instructs the tool to perform *PN* payments.
-- ``--tracks-number=TN`` Instructs the tool to perform *TN* tracking
- operations. Note that the **total** amount of operations will be two
- times *TN*, since "one" tracking operation accounts for
- ``/track/transaction`` and ``/track/transfer``. This command should
- only be used to see if the operation ends without problems, as no
- actual measurement of performance is provided (despite of the
- ’benchmark’ word used in the tool’s name).
-
-
Temporarily Abandoned Features
@@ -1715,5 +1436,5 @@ request to the merchant, for example:
.. code-block:: console
- $ curl http://$(docker-machine ip)/
+ $ wget -O - http://$(docker-machine ip)/
# A greeting message should be returned by the merchant.
diff --git a/taler-merchant-pos-terminal.rst b/taler-merchant-pos-terminal.rst
index 356838fd..efc487cb 100644
--- a/taler-merchant-pos-terminal.rst
+++ b/taler-merchant-pos-terminal.rst
@@ -15,15 +15,22 @@
@author Torsten Grote
-GNU Taler Merchant POS Manual
-#############################
+.. _taler-merchant-pos-app:
-The GNU Taler merchant POS (point of sale) terminal allows sellers to
+Merchant Point of Sale App
+##########################
+
+The GNU Taler merchant point of sale (POS) App allows sellers to
* process customers' orders by adding or removing products
* calculate the amount owed by the customer
* let the customer make a Taler payment via QR code or NFC
+.. contents:: Table of Contents
+ :depth: 1
+ :local:
+
+
Android App
===========
@@ -53,6 +60,7 @@ At the bottom of the main UI there is a row of buttons:
* Prev: Goes to the previous order (if available).
* Next: Goes to the next order or creates a new one
if the current is not empty and there is no next.
+* Data entry: Enter a product name and price manually.
* Complete: Finalize an order and prompt the customer to pay.
The top left corner features a hamburger icon.
@@ -63,38 +71,6 @@ Clicking this opens a menu with these items:
* Settings: Allows you to change the app configuration settings (URL and username/password)
and to forget the password (for locking the app).
-Testing nightly builds
-----------------------
-
-Every change to the app's source code triggers an automatic build
-that gets published in a F-Droid repository.
-If you don't have it already, download the `F-Droid app <https://f-droid.org/>`_
-and then click the following link (on your phone) to add the nightly repository.
-
- `GNU Taler Nightly F-Droid Repository <fdroidrepos://gnu-taler.gitlab.io/fdroid-repo-nightly/fdroid/repo?fingerprint=55F8A24F97FAB7B0960016AF393B7E57E7A0B13C2D2D36BAC50E1205923A7843>`_
-
-.. note::
- Nightly apps can be installed alongside official releases
- and thus are meant **only for testing purposes**.
- Use at your own risk!
-
-While not recommended, APKs can also be
-`downloaded directly <https://gitlab.com/gnu-taler/fdroid-repo-nightly/-/tree/master/fdroid%2Frepo>`__.
-
-Building from source
---------------------
-
-Import in and build with Android Studio or run on the command line:
-
-.. code-block:: console
-
- $ git clone https://git.taler.net/merchant-terminal-android.git
- $ cd merchant-terminal-android
- $ ./gradlew assembleRelease
-
-If you do not have the proprietary Android SDK installed,
-see the :doc:`taler-developer-manual`
-for :ref:`build instructions using free SDK rebuilds <Build-apps-from-source>`.
APIs and Data Formats
=====================
@@ -123,12 +99,9 @@ The elements of the JSON file are defined as follows:
.. ts:def:: BackendConfiguration
interface BackendConfiguration {
- // The URL to the Taler Merchant Backend
+ // The URL to the Taler Merchant Backend (including instance if applicable)
base_url: string;
- // The name of backend instance to be used (see `Backend Options <Backend-options>`)
- instance: string;
-
// The API key used for authentication
api_key: string;
}
diff --git a/taler-monitoring-infrastructure.rst b/taler-monitoring-infrastructure.rst
new file mode 100644
index 00000000..3b809fb3
--- /dev/null
+++ b/taler-monitoring-infrastructure.rst
@@ -0,0 +1,197 @@
+..
+ This file is part of GNU TALER.
+
+ Copyright (C) 2014-2023 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Javier Sepulveda
+.. _taler-merchant-monitoring:
+
+GNU Taler monitoring
+####################
+
+.. image:: images/taler-monitoring-infrastructure.png
+
+In order to check the availability of our server infrastructure, we use the Grafana and Uptime KUMA monitoring programs.
+
+On the one hand Grafana let us to see *graphically* the server consumption resources, and even alert us of some specific situations.
+On the other hand with a more basic tool such as Uptime KUMA (which does mostly ping and https checks),
+we get the very first status information, as the very first countermeasure.
+
+Grafana
+=======
+
+- Our grafana instance can be reached at https://grafana.taler.net
+
+User accounts:
+--------------
+
+We have only two main user accounts:
+
+- One "admin" account for server administrators.
+- One general "read-only" account, for the rest of the team.
+
+How to install Grafana
+----------------------
+
+Please refer to the Grafana official website for installation instructions for your specific operating system. For the
+specific case of the GNU/Linux distribution Debian 12 (bookworm), you can use the next set of instructions.
+
+.. code-block:: console
+
+ # apt-get install -y apt-transport-https
+ # apt-get install -y software-properties-common wget
+ # wget -q -O /usr/share/keyrings/grafana.key https://apt.grafana.com/gpg.key
+ # echo "deb [signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com stable main" | tee -a /etc/apt/sources.list.d/grafana.list
+ # apt update
+ # apt-get install grafana
+ # systemctl daemon-reload
+ # systemctl enable --now grafana-server
+
+.. note::
+
+ If you want to deploy grafana automatically, and if you have access to the --private git repository "migration-exercise-stable.git",
+ please clone it, and execute from Grafana subfolder the grafana.sh file. This script will install for you Grafana and will leave it up and running on port 3000 of your server.
+
+Grafana Dashboards
+------------------
+
+As we understand creating tailored Grafana dashboards, is very time consuming thing to do, and in the top of that
+you really have to to be very proficient to do that, we use the available and pre-built `Grafana dashboards <https://grafana.com/grafana/dashboards/>`_, which eventually we can also tweak a little, to fit our needs.
+
+Node Exporter
+++++++++++++++
+
+- More information can be found on the `Node Exporter <https://grafana.com/grafana/dashboards/1860-node-exporter-full/>`_ website.
+- Dashboard ID: 1860
+
+.. note::
+
+ If you want to deploy Postgres Exporter automatically and have access to the --private git repository "migration-exercise-stable.git", please clone it,
+ and execute from the subfolder taler.net/grafana/node-exporter.sh, this script will install for you Node Exporter and will leave it running on port 9100.
+ This script also will create, start, and enable on reboot a new service.
+
+Postgres Exporter
++++++++++++++++++
+
+- More information can be found on the `PostgreSQL exporter <https://grafana.com/grafana/dashboards/12485-postgresql-exporter/>`_ website.
+- Dashboard ID: 12485
+
+.. image:: images/grafana-postgres-exporter.png
+
+.. note::
+
+ If you want to deploy Postgres Exporter automatically and have access to the --private git repository "migration-exercise-stable.git", please clone it,
+ and execute from the subfolder taler.net/grafana/postgres-exporter.sh, this script will install for you Grafana and will leave it running on port 9187.
+
+Uptime Kuma from Grafana
+++++++++++++++++++++++++
+
+This is an easy to way to integrate all monitored websites from Uptime Kuma, into Grafana. Thus,
+from the same place (Grafana), you can check also the status of the website and the expiration date of the
+certificates.
+
+- More information can be found on the `Uptime Kuma for Grafana <https://grafana.com/grafana/dashboards/18278-uptime-kuma/>`_ website.
+- Dashboard ID: 18278
+
+.. image:: images/uptime-kuma-from-grafana.png
+
+Grafana Data Sources
+---------------------
+As a data source connector we use Prometheus.
+
+Prometheus
+++++++++++
+More information can be found in the `Grafana and Prometheus <https://grafana.com/docs/grafana/latest/getting-started/get-started-grafana-prometheus/>`_ website.
+
+.. note::
+
+ If you want to deploy Prometheus automatically and have access to the --private git repository "migration-exercise-stable.git", please clone it,
+ and execute from the subfolder taler.net/grafana/prometheus.sh, this script will install for you Grafana and will leave it running on port 9090.
+
+Managing logs
+-------------
+
+In order to manage logs, we use Loki + Promtail (Debian packages), which are very easy to integrate with Grafana and Prometheus.
+
+.. code-block:: console
+
+ # Install
+ # apt-get install loki promtail
+ # Start services
+ # systemctl start loki promtail
+ # Enable services on reboot
+ # systemctl enable loki
+ # systemctl enable promtail
+
+Loki and Promtail services in Grafana
+----------------------------------------------
+
+1) Make sure you have prometheus running on port 9090
+2) Make sure you have loki running on port 3100
+
+.. code-block:: console
+
+ systemctl status prometheus loki
+
+
+.. note::
+
+ We still don't have Loki and Promtail installed in production (taler.net), and neither
+ configured to track certain log files.
+
+Grafana Alerting
+----------------
+
+#. In order to use the Grafana alerting system rules, you need first to configure working SMTP service of your server.
+#. Once you have done the necessary changes on the Grafana configuration file, you have to either restart or reload the "grafana-server" service with the systemctl command as usual.
+#. Then go to the Grafana admin panel Alerting -> Contact points, and within the email address you are using for this purpose, check if SMTP is indeed working by pressing the "test" button.
+#. If that works, you will receive an email in your mailbox with the Grafana logo confirming that the server can satisfactorily send email messages.
+
+
+Uptime Kuma
+===========
+
+- URL: http://139.162.254.179:3001/dashboard
+- Users: One single administration account with full privileges.
+- Installation: With Docker
+
+.. image:: images/kuma.png
+
+.. note::
+
+ 1) In order to guarantee the KUMA is doing its work, it needs to be install 100% externally from the servers you want to monitor. (Server Kuma 1)
+ 2) Also, it is important to monitor the KUMA server itself, so you don't endup without a monitoring system. (Server Kuma 2)
+
+In our case, we do both. We have the two Uptime KUMA servers completely outside our server infrastructure, so one monitors the other, and
+the latter one, monitors our own Taler servers.
+
+Kuma monitor types
+-------------------
+
+Kuma counts with quite a few monitor types, such as https, TCP port or ping. In our case, we use mainly https requests,
+and pings, to make sure as a first check that our servers are responsive.
+
+Another handy feature that Kuma has, is the "Certificate Expiry Notification feature, which we also use, and eventually warn us about a certificate
+expiration dates.
+
+So in brief in our KUMA main server, we use these 3 monitor types (ping,https,certificate expiration) for each website that we monitor.
+
+Exceptionally for additional notifications, and specifically due of the importance of the Taler Operations server,
+we use in addition SMS notifications (clicksend provider). This way in case of KUMA detecting the Taler Operations unavailability,
+a SMS message will be sent to at the very least two persons from the deployment and operations department.
+
+How to edit notifications:
+
+.. image:: images/uptime-kuma-edit.png
+
diff --git a/taler-user-guide.rst b/taler-user-guide.rst
new file mode 100644
index 00000000..8e42c0d2
--- /dev/null
+++ b/taler-user-guide.rst
@@ -0,0 +1,328 @@
+..
+ This file is part of GNU TALER.
+ Copyright (C) 2014-2023 Taler Systems SA
+
+ TALER 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.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Christian Grothoff
+
+
+User Guide
+##########
+
+.. contents:: Table of Contents
+ :depth: 1
+ :local:
+
+Introduction
+============
+
+About GNU Taler
+---------------
+
+.. include:: frags/about-taler.rst
+
+
+About this guide
+----------------
+
+This guide explains various ways how users can interact with a GNU Taler
+installation. It assumes that a bank, exchange and merchant backend are
+running and that the user has a GNU Taler wallet installed is able to create
+an account at the bank. Some operations also require access to the merchant
+backend.
+
+
+Withdrawing from bank accounts
+==============================
+
+Withdrawing is the step where money is moved from a bank account into
+a GNU Taler wallet. There are two main ways to do this.
+
+Bank integrated withdrawal
+--------------------------
+
+If the bank supports it, you can withdraw money into your GNU Taler wallet
+directly from your banking app or online banking website. If supported, there
+should be an option in your online banking to withdraw money to a GNU Taler
+wallet. The bank should ask for the amount and then generate a QR code that
+you need to scan with your GNU Taler wallet. Alternatively, if the
+WebExtension wallet is installed, the bank website may directly switch to the
+GNU Taler wallet. In the GNU Taler wallet, you may have to first confirm the
+terms of service of the selected GNU Taler exchange. Afterwards, applicable
+fees will be shown and you will be given the option to accept the withdrawal.
+Next, you need to authorize the withdraw operation in the bank. If possible,
+the GNU Taler wallet may automatically switch to the bank's website, it is
+also possible that you have to go back to the banking app explicitly. After
+authorizing the withdraw operation, you will have to wait a bit for the money
+to be wired to the exchange. Depending on the banking system, this can take
+anywhere from a few seconds to many hours. Afterwards, the money will show up
+in your wallet.
+
+Wallet initiated withdrawal
+---------------------------
+
+In this case, you will start the withdraw process from the GNU Taler wallet.
+Under "Settings", you will find a list of exchanges. If the list is empty or
+does not contain the desired exchange, you may have to first add the exchange
+by providing the respective URL. The payment service provider operating the
+exchange service should have such a QR code on their Web site.
+
+Next to the exchange, there is a drop-down menu with an option to "withdraw".
+(If you already have money in your wallet, you will also find the same button
+when viewing the transaction history of the respective currency.) The wallet
+will ask you to enter the amount to withdraw and accept the terms of service
+and to pay the applicable fees (if any). Afterwards, the wallet will give you
+wire instructions, telling you which amount to wire to which bank account.
+Most importantly, the wallet will give you a wire transfer subject that must
+be specified for the wire transfer. If you make a typo in the subject, the
+wallet will not be topped up and the exchange will send the money back to your
+bank account eventually (possibly minus a fee). Simply make the wire transfer
+as instructed by the wallet. Once the money has arrived at the exchange, the
+wallet will automatically withdraw the funds.
+
+
+Depositing into bank accounts
+=============================
+
+If you have money in your wallet, you can use the "deposit" button to deposit
+the funds into a bank account. The wallet will ask you to specify the amount
+and the target bank account.
+
+
+Sending digital cash
+====================
+
+Once you have digital cash, you can send it to another GNU Taler
+wallet. Simply specify the amount and a human-readable reason for the
+transfer. The wallet will then show a QR code (and give the option to export
+the payment as a taler://-URL). Send the image of the QR code to the
+receiving wallet (or send the taler://-URL securely to the target wallet).
+
+The target wallet should scan the QR code (or enter the text of the
+taler://-URL into the URL import dialog which is available by holding or
+clicking the QR code scan button). Afterwards, review the reason text and
+accept the funds to complete the transaction.
+
+
+Receiving digital cash
+======================
+
+To receive funds from another user, you can send a payment request to another GNU
+Taler wallet. Simply specify the amount and a human-readable reason for the
+payment request. The wallet will then show a QR code (and give the option to export
+the payment request as a taler://-URL). Send the image of the QR code to the payer
+wallet (or send the taler://-URL to the target wallet).
+
+The target wallet should scan the QR code (or enter the text of the
+taler://-URL into the URL import dialog which is available by holding or
+clicking the QR code scan button). Afterwards, review the reason for
+the payment request and decide whether or not to pay it. Selecting
+"pay" will complete the transaction.
+
+Depending on the configuration of the exchange, the receiving wallet may have
+to undergo some KYC check before the funds are actually released to the
+receiver.
+
+
+.. index:: instance
+.. _Instance-account-configuration:
+
+Configuring Accounts at a Merchant Instance
+===========================================
+
+Before you can setup a merchant instance, you need somebody to operate a
+`Taler Merchant Backend <taler-merchant-backend-operator-manual>`_ and `grant
+you access to an instance <Instance-setup>`_ at that backend. For this, you
+should receive the base URL of the instance and an access token.
+
+The main configuration data that must be provided for each instance
+is the bank account information.
+
+In order to receive payments, the merchant backend needs to
+communicate bank account details to the exchange.
+
+The bank account information is provided in the form of a ``payto://``-URI.
+See `RFC 8905 <https://tools.ietf.org/html/rfc8905>`_
+for the format of ``payto://``-URIs. Note that the "receiver-name" is
+optional in RFC 8905 but mandatory in GNU Taler.
+
+For first tests, you may want to sign up for a KUDOS bank account at
+`https://bank.demo.taler.net/ <https://bank.demo.taler.net/>`_. In this case,
+the ``payto://``-URI will be of the form
+``payto://iban/$IBAN?receiver-name=$NAME`` where ``$IBAN`` must be replaced
+with the IBAN shown on the main page of the account shown at
+`https://bank.demo.taler.net/ <https://bank.demo.taler.net/>`_ after logging
+in.
+
+When deploying Taler with the real banking system, you primarily need to
+change the currency of the configuration from KUDOS to the actual currency
+(such as EUR, USD, CHF) and provide a ``payto://``-URI of your actual bank
+account. In Europe, this will involve knowing your IBAN number. If you have an
+IBAN, the corresponding ``payto://``-URI is simply
+``payto://iban/$IBAN?receiver-name=$NAME`` where ``$IBAN`` must be replaced
+with the actual IBAN number and ``$NAME`` with your actual name. Make sure to
+URI-encode your name. The merchant SPA will do this automatically when you
+use it to configure the bank account.
+
+
+
+Using the Point-of-Sale App
+===========================
+
+A simple way for merchants to accept GNU Taler payments is the use of the
+point-of-sale app. The app can be installed on an Android phone or tablet
+and is configured via a simple JSON file on a Web site:
+
+* In the app settings you need to specify the URL of the Web site where
+ the app can download the categories, products and prices from which
+ orders are to be compiled. You can optionally specify a username and
+ password to authenticate to the Web server.
+
+* The syntax of the JSON file is described in the point-of-sale app
+ manual. However, you may simply want to download the sample JSON
+ file from our documentation and use it as a starting point.
+
+* A key option is the merchant backend with the authorization key
+ which must be included in this JSON configuration. You may point
+ the point-of-sale app to any instance of a merchant backend.
+
+Once configured, the point-of-sale app allows the user to select a product
+category and then to quickly add products from that category to an order. You
+can easily edit the order, and finally use the "complete" button to generate a
+QR code. The QR code must then be scanned by the GNU Taler wallet to initiate
+the payment. Multiple orders can be entered concurrently, for example in a
+restaurant where multiple tables are waited on at the same time.
+
+
+Setting up an order in the merchant backoffice SPA
+==================================================
+
+Arbitrary orders can also be created manually using the Web interface of
+the GNU Taler merchant backend. For this, log into the single page app (SPA)
+of the merchant backend using the authorization token of the respective
+instance you want to use.
+
+You can then set up orders by providing all of the required fields of an
+order, in particular an order summary and a price. You can also set various
+optional fields or override instance default settings.
+
+When the order has been setup, you can follow a link to the payment page
+which will show the QR code (and/or URL) that a GNU Taler wallet would need
+to receive to initiate the payment process. The order status page also
+shows you the progress of the order, including when a wallet has made the
+payment. You can also use the backend to approve refunds.
+
+
+Paying an order
+===============
+
+The payer simply scans the (dynamic) QR code to initiate the payment. If a
+website is interacting with a WebExtension wallet, it may also directly
+trigger the GNU Taler wallet without requiring the user to explicitly scan the
+QR code. The payer should now review the contract terms and applicable fees.
+Selecting "pay" will complete the transaction. Typically, the wallet will
+then redirect the user to the fulfillment page where they can track the order
+or directly view the digital product that they purchased.
+
+
+Setting up a template
+=====================
+
+A template provides all or part of the information needed to setup an order
+and allows GNU Taler wallets to create an order. Usually, the creation of
+orders is a privileged process that requires knowledge of the authorization
+code for the respective instance. With templates, a customer's wallet can
+directly create an order on-demand. The information of a template can be
+partial, in which case the customer is expected to provide the remaining
+details, typically the summary and/or amount of the order.
+
+When setting up a template you need to specify all of the fixed inputs that
+the customer cannot change. You can then generate a template QR code where
+you may additionally specify editable defaults for the order, such as a
+default summary or a default amount which may still be changed by the wallet.
+The resulting template QR code encodes the specific merchant backend, instance
+and template ID as well as the (editable) default values. The resulting
+static QR code can then be printed and put on display.
+
+Customers can scan the QR code with their GNU Taler wallet, complete the
+missing details or edit the defaults (if any), and pay the resulting order.
+
+To secure template-based payments, you may specify a TOTP secret as part of
+the template. In this case, the merchant backend will send a set of TOTP
+payment confirmation codes to the GNU Taler wallet upon receiving a payment
+for an order created based on the template. If the point-of-sale has a TOTP
+generator with the same secret, they can compare their TOTP code with the
+codes shown by the customer on their wallet. This provides additional
+assurance that the customer actually made the payment instead of just showing
+a fake confirmation screen.
+
+
+Paying with static QR codes
+===========================
+
+The payer simply scans the (static) QR code to initiate the payment. If the
+template does not specify a fixed amount, the payer will be prompted to enter
+the amount to be paid (and possibly given the opportunity to specify or alter
+the summary). Selecting "pay" will complete the transaction. If payment
+confirmations are configured by the merchant backend, the wallet will then
+display a TOTP confirmation code that can be shown to the merchant as a proof
+of payment.
+
+
+
+Setting up a webhook
+====================
+
+To receive notifications when a purchase has been made or a refund was given
+to a wallet, you can set up webhooks in the GNU Taler merchant backend.
+Webhooks allow you to trigger HTTP(S) requests based on certain events. A
+webhook is thus simply an HTTP request that the GNU Taler merchant backend
+will make when a certain event (such as a payment) happens.
+
+There are various providers that can send an SMS to a phone number based on an
+HTTP request. Thus, by configuring such a provider in a webhook you can
+receive an SMS notification whenever a customer makes a payment.
+
+Webhooks are configured per instance. In the Webhook configuration,
+you can specify which URL, which HTTP headers, which HTTP method and what HTTP
+body to send to the Webhook. Webhooks are automatically retried (with
+increasing delays) when the target server returns a temporary error.
+
+`Mustach templates <https://mustache.github.io/mustache.5.html>`__ are used
+when defining the contents of Webhooks. Depending on the triggering event,
+the templates will be expanded with event-specific data.
+
+
+Pay events
+----------
+
+For "pay" events, the backend will provide the following
+information to the Mustach templating engine:
+
+* :ref:`contract_terms <contract-terms>`: the contract terms of the paid order
+* order_id: the ID of the order that received the refund
+
+
+Refund events
+-------------
+
+For "refund" events, the backend will provide the following information to the
+Mustach templating engine:
+
+* timestamp: time of the refund (in nanoseconds since 1970)
+* order_id: the ID of the order that received the refund
+* :ref:`contract_terms <contract-terms>`: the full JSON of the contract terms of the refunded order
+* refund_amount: the amount that was being refunded
+* reason: the reason entered by the merchant staff for granting the refund;
+ be careful, you probably want to inform your staff if a webhook may expose
+ this information to the consumer
diff --git a/taler-wallet-cli-manual.rst b/taler-wallet-cli-manual.rst
deleted file mode 100644
index 0758f9ef..00000000
--- a/taler-wallet-cli-manual.rst
+++ /dev/null
@@ -1,138 +0,0 @@
-GNU Taler Wallet CLI Manual
-###########################
-
-This manual describes how to use the GNU Taler wallet command line
-interface (CLI).
-
-The the wallet CLI is targeted at developers and operators, but not meant to be
-used by customers. It exposes all functionality that the more user-friendly
-interfaces (Android app, browser extension) offer. However, it provides more
-diagnostics and advanced features as well.
-
-Installation
-------------
-
-The easiest way to install the wallet is via NPM. Note that a recent version of
-Node.JS (``>=12.20.1``) is required.
-
-We recommend to install the wallet package on a per-user basis.
-To do so, configure node and adjust your ``$PATH``:
-
-.. code-block:: console
-
- $ npm set prefix $HOME/.npm-global
- $ export PATH=$HOME/.npm-global:$PATH
-
-Now the wallet CLI can be installed without requiring elevated permissions:
-
-.. code-block:: console
-
- $ npm set prefix $HOME/.npm-global
- $ npm install -g @gnu-taler/taler-wallet-cli
- $ taler-wallet-cli --version
-
-
-Getting Help
-------------
-
-The wallet CLI comes with built-in help. Invoke the wallet CLI (or any subcommand) with the ``--help`` flag to get help:
-
-.. code-block:: console
-
- $ taler-wallet-cli --help
- Usage: taler-wallet-cli COMMAND
-
- Command line interface for the GNU Taler wallet.
-
- Options:
- -h, --help Show this message and exit.
- --wallet-db=VALUE location of the wallet database file
- --timetravel=VALUE modify system time by given offset in microseconds
- --inhibit=VALUE Inhibit running certain operations, useful for debugging and testing.
- --no-throttle Don't do any request throttling.
- -v, --version
- -V, --verbose Enable verbose output.
-
- Commands:
- advanced Subcommands for advanced operations (only use if you know what you're doing!).
- api Call the wallet-core API directly.
- backup Subcommands for backups
- balance Show wallet balance.
- deposit Subcommands for depositing money to payto:// accounts
- exchanges Manage exchanges.
- handle-uri Handle a taler:// URI.
- pending Show pending operations.
- run-pending Run pending operations.
- run-until-done Run until no more work is left.
- testing Subcommands for testing GNU Taler deployments.
- transactions Show transactions.
-
-Completing operations
----------------------
-
-Note that the CLI does not run as a background daemon. When starting
-operations that don't immediately finish, the wallet needs to be run explicitly
-to finish any pending tasks:
-
-
-.. code-block:: console
-
- # Do one attempt to finish all pending operations
- $ taler-wallet-cli run-pending
-
- # Run until all work is done
- $ taler-wallet-cli run-until-done
-
-Resetting the wallet
---------------------
-
-The wallet can be reset by deleting its database file. By default, the database file
-is ``$HOME/.talerwalletdb.json``.
-
-
-Handling taler:// URIs
-----------------------
-
-Many interactions with the Taler wallet happen by scanning QR codes or special
-headers on Websites. To emulate this with the command line interface, run the following
-command:
-
-.. code-block:: console
-
- $ taler-wallet-cli handle-uri $URI
-
-
-Testing an exchange deployment
-------------------------------
-
-The following series of commands can be used to check that an exchange deployment
-is functional:
-
-.. code-block:: console
-
- # This will now output a payto URI that money needs to be sent to in order to allow withdrawal
- # of taler coins
- $ taler-wallet-cli advanced withdraw-manually --exchange $EXCHANGE_URL --amount EUR:10.50
-
- # Show the status of the manual withdrawal operation
- $ taler-wallet-cli transactions
-
- # Once the transfer has been made, try completing the withdrawal
- $ taler-wallet-cli run-pending
-
- # Check status of transactions and show balance
- $ taler-wallet-cli transactions
- $ taler-wallet-cli balance
-
- # Now, directly deposit coins with the exchange into a target account
- # (Usually, a payment is made via a merchant. The wallet provides
- # this functionality for testing.)
- $ taler-wallet-cli deposit create EUR:5 payto://sepa/$IBAN
-
- # Check if transaction was successful.
- # (If not, fix issue with exchange and run "run-pending" command again)
- $ taler-wallet-cli transactions
-
- # The wallet can also track if the exchange wired the money to the merchant account.
- # The "deposit group id" can be found in the output of the transactions list.
- $ taler-wallet-cli deposit track $DEPOSIT_GROUP_ID
diff --git a/taler-wallet.rst b/taler-wallet.rst
index 4de69520..4a975340 100644
--- a/taler-wallet.rst
+++ b/taler-wallet.rst
@@ -1,65 +1,28 @@
-GNU Taler Wallet Developer Manual
-#################################
+..
+ This file is part of GNU TALER.
+ Copyright (C) 2014-2024 Taler Systems SA
-The GNU Taler wallet allows customers to withdraw and spend digital cash.
-
-.. _command-line-wallet:
-
-Command-line Wallet
-===================
-
-The command-line wallet is used primarily for testing by developers.
-
-Building from source
---------------------
-
-.. code-block:: console
-
- $ git clone https://git.taler.net/wallet-core.git
- $ cd wallet-core
- $ ./bootstrap
- $ ./configure --prefix=$INSTALL_PREFIX
- $ make && make install
-
-The wallet command-line interface should then be available as ``taler-wallet-cli`` under ``$INSTALL_PREFIX/bin``.
-
-Installation via NPM
---------------------
+ TALER 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.
-The wallet can also obtained via NPM, the Node Package Manager.
-
-To install the wallet as a global package, run:
+ 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 Affero General Public License for more details.
-.. code-block:: console
-
- $ npm install -g taler-wallet
- # check if installation was successful
- $ taler-wallet-cli --version
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-To install the wallet only for your user, run:
-.. code-block:: console
+Wallet Manual
+#############
- $ npm install -g --prefix=$HOME/local taler-wallet
- # check if installation was successful
- $ taler-wallet-cli --version
- # If this fails, make sure that $HOME/local/bin is in your $PATH
-
-To use the wallet as a library in your own project, run:
-
-.. code-block:: console
-
- $ npm install taler-wallet
-
-
-Manual withdrawing
-==================
+The GNU Taler wallet allows customers to withdraw and spend digital cash.
-.. code-block:: console
+.. contents:: Table of Contents
+ :depth: 1
+ :local:
- $ taler-wallet-cli advanced withdraw-manually \
- --exchange https://exchange.eurint.taler.net/ \
- --amount EUR:5
WebExtension Wallet
===================
@@ -83,556 +46,344 @@ Android Wallet
Please see :ref:`Build-apps-from-source` in the :doc:`taler-developer-manual`.
-APIs and Data Formats
-=====================
+iOS Wallet
+==========
-.. warning::
+Please see :ref:`Build-iOS-from-source` in the :doc:`taler-developer-manual`.
- These APIs are still a work in progress and *not* final.
+.. _command-line-wallet:
-Envelope Format
----------------
+Command-line Wallet
+===================
-All API responses and notifications are returned in the
-following envelope:
+This section describes how to use the GNU Taler wallet command line
+interface (CLI).
-.. ts:def:: WalletResponseEnvelope
+The the wallet CLI is targeted at developers and operators, but not meant to be
+used by customers. It exposes all functionality that the more user-friendly
+interfaces (Android app, browser extension) offer. However, it provides more
+diagnostics and advanced features as well.
- type WalletResponseEnvelope =
- | WalletSuccess
- | WalletError
- | WalletNotification
+Building from source
+--------------------
-.. ts:def:: WalletSuccess
+The easiest way to install the wallet is via NPM. Note that a recent version of
+Node.JS (``>=12.20.1``) is required.
- export interface WalletSuccess {
- type: "response";
- operation: string,
- // ID to correlate success response to request
- id: string;
- // Result type depends on operation
- result: unknown;
- }
+We recommend to install the wallet package on a per-user basis,
+thus setting ``$INSTALL_PREFIX`` to a directory in ``$HOME``.
-.. ts:def:: WalletError
+.. code-block:: console
- export interface WalletError {
- type: "error";
- operation: string,
- // ID to correlate error response to request
- id: string;
- error: WalletErrorInfo;
- }
+ $ git clone https://git.taler.net/wallet-core.git
+ $ cd wallet-core
+ $ ./bootstrap
+ $ ./configure --prefix=$INSTALL_PREFIX
+ $ make && make install
-.. ts:def:: WalletNotification
+The wallet command-line interface should then be available as ``taler-wallet-cli`` under ``$INSTALL_PREFIX/bin``.
- export interface WalletSuccess {
- type: "notification";
+Installation via NPM
+--------------------
- // actual type is WalletNotification,
- // to be documented here
- payload: any;
- }
+The wallet can also obtained via NPM, the Node Package Manager.
-.. ts:def:: WalletErrorInfo
+To install the wallet as a global package, run:
- export interface WalletErrorInfo {
- // Numeric error code defined defined in the
- // GANA gnu-taler-error-codes registry.
- talerErrorCode: number;
+.. code-block:: console
- // English description of the error code.
- talerErrorHint: string;
+ $ npm install -g taler-wallet
+ # check if installation was successful
+ $ taler-wallet-cli --version
- // English diagnostic message that can give details
- // for the instance of the error.
- message: string;
+To install the wallet only for your user, run:
- // Error details, type depends
- // on talerErrorCode
- details: unknown;
- }
+.. code-block:: console
-Balances
---------
+ $ npm install -g --prefix=$HOME/local taler-wallet
+ # check if installation was successful
+ $ taler-wallet-cli --version
+ # If this fails, make sure that $HOME/local/bin is in your $PATH
-Balances are the amounts of digital cash held by the wallet.
+To use the wallet as a library in your own project, run:
-:name: ``"getBalances"``
-:description: Get a list of balances per currency.
-:response:
- .. ts:def:: BalancesResponse
+.. code-block:: console
- interface BalancesResponse {
- // a list of balances sorted by currency.
- // (currencies with shorter names first, then lexically ascending).
- //
- // Note: Even when a currency has no balance, but pending or past transactions,
- // it should be included in this list with a balance of zero.
- balances: Balance[];
- }
+ $ npm install taler-wallet
- .. ts:def:: Balance
-
- // Balance for one currency.
- // The currency can be derived from any of the
- // "Amount" fields, as the currency is present even
- // when the amount is zero.
- interface Balance {
- // The total Amount that is currently available to be spent
- // including amounts tied up in ongoing refresh operations. These are hidden from the user.
- // If the user tries to spend coins locked up this way,
- // the wallet will give an error message different from "insufficient balance".
- available: Amount;
-
- // the total incoming amount that will be added to the available balance
- // when all pending transactions succeed (including internal refreshes)
- pendingIncoming: Amount;
-
- // the total outgoing amount that will be subtracted from the available balance
- // when all pending transactions succeed (including internal refreshes)
- pendingOutgoing: Amount;
-
- // true if the balance requires user-interaction, e.g. accepting a tip
- // (DEV: can be left out of a first implementation)
- requiresUserInput: boolean;
- }
-Transactions
+Getting Help
------------
-Transactions are all operations or events that affect the balance.
-
-:Name: ``"getTransactions"``
-:Description: Get a list of past and pending transactions.
-:Request:
- .. ts:def:: TransactionsRequest
-
- interface TransactionsRequest {
- // return only transactions in the given currency, if present
- currency?: string;
-
- // if present, results will be limited to transactions related to the given search string
- search?: string;
- }
-:Response:
- .. ts:def:: TransactionsResponse
-
- interface TransactionsResponse {
- // a list of past and pending transactions sorted by pending, timestamp and transactionId.
- // In case two events are both pending and have the same timestamp,
- // they are sorted by the transactionId
- // (i.e. pending before non-pending transactions, newer before older
- // and if all equal transactionId lexically ascending).
- transactions: Transaction[];
- }
-
- .. ts:def:: Transaction
-
- interface Transaction {
- // opaque unique ID for the transaction, used as a starting point for paginating queries
- // and for invoking actions on the transaction (e.g. deleting/hiding it from the history)
- transactionId: string;
-
- // the type of the transaction; different types might provide additional information
- type: TransactionType;
-
- // main timestamp of the transaction
- timestamp: Timestamp;
+The wallet CLI comes with built-in help. Invoke the wallet CLI (or any subcommand) with the ``--help`` flag to get help:
- // true if the transaction is still pending, false otherwise
- // If a transaction is not longer pending, its timestamp will be updated,
- // but its transactionId will remain unchanged
- pending: boolean;
-
- // if present, the transaction encountered a fatal error that needs to be shown to the user
- error?: TransactionError;
-
- // Raw amount of the transaction (exclusive of fees or other extra costs)
- amountRaw: Amount;
-
- // Amount added or removed from the wallet's balance (including all fees and other costs)
- amountEffective: Amount;
- }
-
- .. ts:def:: TransactionType
-
- type TransactionType = (
- TransactionWithdrawal |
- TransactionPayment |
- TransactionRefund |
- TransactionTip |
- TransactionRefresh
- )
-
- .. ts:def:: TransactionError
-
- interface TransactionError {
- // TALER_EC_* unique error code.
- // The action(s) offered and message displayed on the transaction item depend on this code.
- ec: number;
-
- // English-only error hint, if available.
- hint?: string;
-
- // Error details specific to "ec", if applicable/available
- details?: any;
- }
-
- .. ts:def:: WithdrawalDetails
-
- export type WithdrawalDetails =
- | WithdrawalDetailsForManualTransfer
- | WithdrawalDetailsForTalerBankIntegrationApi;
-
- .. ts:def:: WithdrawalDetailsForManualTransfer
-
- interface WithdrawalDetailsForManualTransfer {
- type: "manual-transfer";
-
- // Payto URIs that the exchange supports.
- // Already contains the amount and message.
- exchangePaytoUris: string[];
-
- // Public key of the newly created reserve.
- // Not useful for the UI, but required for integration testing.
- reservePub: string;
- }
-
- .. ts:def:: WithdrawalDetailsForTalerBankIntegrationApi
-
- interface WithdrawalDetailsForTalerBankIntegrationApi {
- type: "taler-bank-integration-api";
-
- // Set to true if the bank has confirmed the withdrawal, false if not.
- // An unconfirmed withdrawal usually requires user-input and should be highlighted in the UI.
- // See also bankConfirmationUrl below.
- confirmed: boolean;
-
- // If the withdrawal is unconfirmed, this can include a URL for user
- // initiated confirmation.
- bankConfirmationUrl?: string;
- }
-
- .. ts:def:: TransactionWithdrawal
-
- // This should only be used for actual withdrawals
- // and not for tips that have their own transactions type.
- interface TransactionWithdrawal extends Transaction {
- type: string = "withdrawal",
-
- // Exchange that was withdrawn from.
- exchangeBaseUrl: string;
-
- // Amount that has been subtracted from the reserve's balance for this withdrawal.
- amountRaw: Amount;
-
- // Amount that actually was (or will be) added to the wallet's balance.
- // Should always be shown as a positive amount.
- amountEffective: Amount;
+.. code-block:: console
- // Further details
- withdrawalDetails: WithdrawalDetails;
- }
+ $ taler-wallet-cli --help
+ Usage: taler-wallet-cli COMMAND
+
+ Command line interface for the GNU Taler wallet.
+
+ Options:
+ -h, --help Show this message and exit.
+ --wallet-db=VALUE location of the wallet database file
+ --timetravel=VALUE modify system time by given offset in microseconds
+ --inhibit=VALUE Inhibit running certain operations, useful for debugging and testing.
+ --no-throttle Don't do any request throttling.
+ -v, --version
+ -V, --verbose Enable verbose output.
+
+ Commands:
+ advanced Subcommands for advanced operations (only use if you know what you're doing!).
+ api Call the wallet-core API directly.
+ backup Subcommands for backups
+ balance Show wallet balance.
+ deposit Subcommands for depositing money to payto:// accounts
+ exchanges Manage exchanges.
+ handle-uri Handle a taler:// URI.
+ pending Show pending operations.
+ run-pending Run pending operations.
+ run-until-done Run until no more work is left.
+ testing Subcommands for testing GNU Taler deployments.
+ transactions Show transactions.
+
+Completing operations
+---------------------
+
+Note that the CLI does not run as a background daemon. When starting
+operations that don't immediately finish, the wallet needs to be run explicitly
+to finish any pending tasks:
- .. ts:def:: TransactionPayment
- interface TransactionPayment extends Transaction {
- type: string = "payment",
+.. code-block:: console
- // Additional information about the payment.
- info: OrderShortInfo;
+ # Do one attempt to finish all pending operations
+ $ taler-wallet-cli run-pending
- // Wallet-internal end-to-end identifier for the payment
- // (assigned before the order is even downloaded, thus the name).
- proposalId: string;
+ # Run until all work is done
+ $ taler-wallet-cli run-until-done
- // The current status of this payment.
- status: PaymentStatus;
+Resetting the wallet
+--------------------
- // Amount that must be paid for the contract
- amountRaw: Amount;
+The wallet can be reset by deleting its database file. By default, the database file
+is ``$HOME/.talerwalletdb.json``.
- // Amount that was paid, including deposit, wire and refresh fees.
- // Should always be shown as a negative amount.
- amountEffective: Amount;
- }
- .. ts:def:: OrderShortInfo
+Handling taler:// URIs
+----------------------
- interface OrderShortInfo {
- // Order ID, uniquely identifies the order within a merchant instance
- orderId: string;
+Many interactions with the Taler wallet happen by scanning QR codes or special
+headers on Websites. To emulate this with the command line interface, run the following
+command:
- // More information about the merchant
- merchant: Merchant;
+.. code-block:: console
- // Summary of the order, given by the merchant
- summary: string;
+ $ taler-wallet-cli handle-uri $URI
- // Map from IETF BCP 47 language tags to localized summaries
- summary_i18n?: { [lang_tag: string]: string };
- // List of products that are part of the order
- products: Product[];
+Manual withdrawing
+------------------
- // URL of the fulfillment, given by the merchant
- fulfillmentUrl?: string;
+.. code-block:: console
- // Message shown to the user after the payment is complete.
- fulfillmentMessage?: string;
+ $ taler-wallet-cli advanced withdraw-manually \
+ --exchange https://exchange.eurint.taler.net/ \
+ --amount EUR:5
- // Map from IETF BCP 47 language tags to localized fulfillment messages
- fulfillmentMessage_i18n: { [lang_tag: string]: string };
- }
- .. ts:def:: PaymentStatus
+P2P push payments
+-----------------
- enum PaymentStatus {
- // Explicitly aborted after timeout / failure
- Aborted = "aborted",
+The following code generates a P2P push transaction over 1 CHF
+with an expiration time of 30 days (assuming the wallet has a
+sufficient balance):
- // Payment failed, wallet will auto-retry.
- // User should be given the option to retry now / abort.
- Failed = "failed",
+.. code-block:: console
- // Paid successfully
- Paid = "paid",
+ $ taler-wallet-cli p2p initiate-push-debit \
+ --purse-expiration="30 d" \
+ --summary="The summary" \
+ CHF:1
- // Only offered, user must accept / decline
- Offered = "offered",
+The final URL can then be found in the transaction list:
- // User accepted, payment is processing.
- Accepted = "accepted",
- }
+.. code-block:: console
- .. ts:def:: TransactionRefund
+ $ taler-wallet-cli transactions
- interface TransactionRefund extends Transaction {
- type: string = "refund",
+Background wallet
+-----------------
- // ID for the transaction that is refunded
- refundedTransactionId: string;
+A wallet can be launched in the background:
- // Additional information about the refunded payment
- info: OrderShortInfo;
+.. code-block:: console
- // Part of the refund that couldn't be applied because the refund permissions were expired
- amountInvalid: Amount;
+ $ taler-wallet-cli advanced serve &
- // Amount that has been refunded by the merchant.
- // Corresponds to amountRefundGranted from the applyRefund response.
- amountRaw: Amount;
+You can then run various Taler operations faster against
+this one persistent instance:
- // Amount will be added to the wallet's balance after fees and refreshing.
- // Should always be shown as a positive amount.
- amountEffective: Amount;
- }
+.. code-block:: console
- .. ts:def:: TransactionTip
+ $ taler-wallet-cli --wallet-connection=wallet-core.sock ...
- interface TransactionTip extends Transaction {
- type: string = "tip",
+Here ``...`` needs to be changed to the commando to run.
+Make sure to run
- // The current status of this tip.
- status: TipStatus;
+.. code-block:: console
- // Exchange that the tip will be (or was) withdrawn from
- exchangeBaseUrl: string;
+ $ taler-wallet-cli --wallet-connection=wallet-core.sock \
+ run-until-done
- // More information about the merchant that sent the tip
- merchant: Merchant;
+to wait for pending transactions to complete.
- // Raw amount of the tip, without extra fees that apply
- amountRaw: Amount;
- // Amount will be (or was) added to the wallet's balance after fees and refreshing.
- // Should always be shown as a positive amount.
- amountEffective: Amount;
- }
+Testing an exchange deployment
+------------------------------
- .. ts:def:: TipStatus
+The following series of commands can be used to check that an exchange deployment
+is functional:
- enum TipStatus {
- // Only offered, user must accept / decline
- Offered = "offered",
+.. code-block:: console
- // User accepted, tip is processing.
- Accepted = "accepted",
+ # This will now output a payto URI that money needs to be sent to in order to allow withdrawal
+ # of taler coins
+ $ taler-wallet-cli advanced withdraw-manually --exchange $EXCHANGE_URL --amount EUR:10.50
- // User declined.
- Declined = "declined",
+ # Show the status of the manual withdrawal operation
+ $ taler-wallet-cli transactions
- // Received successfully
- Received = "received",
- }
+ # Once the transfer has been made, try completing the withdrawal
+ $ taler-wallet-cli run-pending
- .. ts:def:: TransactionRefresh
+ # Check status of transactions and show balance
+ $ taler-wallet-cli transactions
+ $ taler-wallet-cli balance
- // A transaction shown for refreshes that are not associated to other transactions
- // such as a refresh necessary before coin expiration.
- // It should only be returned by the API if the effective amount is different from zero.
- interface TransactionRefresh extends Transaction {
- type: string = "refresh",
+ # Now, directly deposit coins with the exchange into a target account
+ # (Usually, a payment is made via a merchant. The wallet provides
+ # this functionality for testing.)
+ $ taler-wallet-cli deposit create EUR:5 payto://iban/$IBAN
- // Exchange that the coins are refreshed with
- exchangeBaseUrl: string;
+ # Check if transaction was successful.
+ # (If not, fix issue with exchange and run "run-pending" command again)
+ $ taler-wallet-cli transactions
- // Raw amount that is refreshed
- amountRaw: Amount;
+ # The wallet can also track if the exchange wired the money to the merchant account.
+ # The "deposit group id" can be found in the output of the transactions list.
+ $ taler-wallet-cli deposit track $DEPOSIT_GROUP_ID
- // Amount that will be paid as fees for the refresh.
- // Should always be shown as a negative amount.
- amountEffective: Amount;
- }
+.. _withdraw-simulation:
-:Name: ``"deleteTransaction"``
-:Description: Delete a transaction by ID.
-:Request:
- .. ts:def:: DeleteTransactionRequest
+Paying for an order
+===================
- interface DeleteTransactionRequest {
- // Transaction ID (opaque!) as returned in
- // the transaction list response.
- transactionId: string;
- }
-:Response: Returns an empty object
+.. note::
-Refunds
--------
+ This section is in dire need for some editing...
-:Name: ``"applyRefund"``
-:Description: Process a refund from a ``taler://refund`` URI.
-:Request:
- .. ts:def:: WalletApplyRefundRequest
+This section explains how to pay for an order in a scenario where the fiat bank
+is simulated. The simulation takes place by crafting ad-hoc XML files as if the
+bank would have issued them. Such XML files carry information about incoming payments
+to the regional currency master bank account. Finally, the XML files are passed
+to LibEuFin nexus via a convenient CLI method. The responsible script for such
+simulation is ``withdraw.sh``.
- interface WalletApplyRefundRequest {
- talerRefundUri: string;
- }
-:Response:
- .. ts:def:: WalletApplyRefundResponse
+Run ``./withdraw.sh`` without any arguments. Assuming that you ran the command
+as the ``test-user``, after the execution, 5 units of the regional currency should
+be found in the CLI wallet owned by ``test-user``.
- interface WalletApplyRefundResponse {
- // Identifier for the purchase that was refunded
- // DEPRECATED: Will disappear soon.
- contractTermsHash: string;
- amountEffectivePaid: Amount;
+Check it with:
- amountRefundGranted: Amount;
+.. code-block:: console
- amountRefundGone: Amount;
+ $ taler-wallet-cli balance
- pendingAtExchange: boolean;
+If so, call the wallet in the following way to finally pay for the order just created:
- // Short info about the order being refunded.
- info: OrderShortInfo;
- }
+.. code-block:: console
-Exchange Management
--------------------
+ $ taler-wallet-cli handle-uri "$TALER_PAY_URI"
-List Exchanges
-~~~~~~~~~~~~~~
+.. note::
-:Name: ``"listExchanges"``
-:Description:
- List all exchanges.
-:Response:
- .. ts:def:: ExchangesListResponse
+ Reset the state before going to production, as it impacts the way nexus
+ asks records to the bank. In particular, delete: any database and the
+ files ``config/user.conf`` and ``config/internal.conf``, and finally run
+ ``./main.sh`` again.
- interface ExchangesListResponse {
- exchanges: ExchangeListItem[];
- }
- .. ts:def:: ExchangeListItem
- interface ExchangeListItem {
- exchangeBaseUrl: string;
- currency: string;
- paytoUris: string[];
- }
-Add Exchange
-~~~~~~~~~~~~
-:Name: ``"addExchange"``
-:Description:
- Add an exchange.
-:Request:
- .. ts:def:: ExchangeAddRequest
+APIs and Data Formats
+=====================
- interface ExchangeAddRequest {
- exchangeBaseUrl: string;
- }
-:Response:
- On success, the response is an `ExchangeListItem`.
+Envelope Format
+---------------
+All API responses and notifications are returned in the
+following envelope:
-Force Exchange Update
-~~~~~~~~~~~~~~~~~~~~~
+.. ts:def:: WalletResponseEnvelope
-:Name: ``"forceUpdateExchange"``
-:Description:
- Force updating an exchange.
- Re-queries current cryptographic key material, wire information
- and terms of service from the exchange. Also applies denomination revocations
- if applicable.
-:Request:
- .. ts:def:: ExchangeForceUpdateRequest
+ type WalletResponseEnvelope =
+ | WalletSuccess
+ | WalletError
+ | WalletNotification
- interface ExchangeForceUpdateRequest {
- exchangeBaseUrl: string;
- }
-:Response:
- On success, the response is an `ExchangeListItem`.
+.. ts:def:: WalletSuccess
+ export interface WalletSuccess {
+ type: "response";
+ operation: string;
+ // ID to correlate success response to request
+ id: string;
+ // Result type depends on operation
+ result: unknown;
+ }
-Get Terms of Service
-~~~~~~~~~~~~~~~~~~~~
+.. ts:def:: WalletError
-:Name: ``"getExchangeTos"``
-:Description:
- Get the exchange's current ToS and which version of the ToS (if any)
- the user has accepted.
-:Request:
- .. ts:def:: ExchangeGetTosRequest
+ export interface WalletError {
+ type: "error";
+ operation: string;
+ // ID to correlate error response to request
+ id: string;
+ error: WalletErrorInfo;
+ }
- interface ExchangeGetTosRequest {
- exchangeBaseUrl: string;
- }
-:Response:
- .. ts:def:: ExchangeGetTosResult
+.. ts:def:: WalletNotification
- interface GetExchangeTosResult {
- // Markdown version of the current ToS.
- tos: string;
+ export interface WalletSuccess {
+ type: "notification";
- // Version tag of the current ToS.
- currentEtag: string;
+ // actual type is WalletNotification,
+ // to be documented here
+ payload: any;
+ }
- // Version tag of the last ToS that the user has accepted,
- // if any.
- acceptedEtag: string | undefined;
- }
+.. ts:def:: WalletErrorInfo
-Set Accepted Terms of Service Version
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ export interface WalletErrorInfo {
+ // Numeric error code defined defined in the
+ // GANA gnu-taler-error-codes registry.
+ talerErrorCode: number;
-:Name: ``"setExchangeTosAccepted"``
-:Description:
- Store that the user has accepted a version of the exchange's ToS.
-:Request:
- .. ts:def:: ExchangeSetTosAccepted
+ // English description of the error code.
+ talerErrorHint: string;
- interface ExchangeGetTosRequest {
- exchangeBaseUrl: string;
- acceptedEtag: string;
- }
-:Response:
- On success, the response is an empty object.
+ // English diagnostic message that can give details
+ // for the instance of the error.
+ message: string;
+ // Error details, type depends
+ // on talerErrorCode
+ details: unknown;
+ }
Withdrawal
----------
@@ -657,464 +408,6 @@ A typical API sequence for *manual* withdrawals can for example look like this:
#. ``"acceptManualWithdrawal"`` after the user confirmed withdrawal with associated fees
-Get Details For Bank-integrated Withdrawal
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-:Name: ``"getWithdrawalDetailsForUri"``
-:Description:
- Get information about exchanges for a bank-integrated withdrawal from a ``taler://withdraw`` URI.
-:Request:
- .. ts:def:: GetWithdrawalUriDetailsRequest
-
- interface GetWithdrawalUriDetailsRequest {
- talerWithdrawUri: string;
- }
-:Response:
- .. ts:def:: WithdrawalDetailsForUri
-
- interface WithdrawalDetailsForUri {
- // The amount that the user wants to withdraw
- amount: Amount;
-
- // Exchange suggested by the wallet
- defaultExchangeBaseUrl?: string;
-
- // A list of exchanges that can be used for this withdrawal
- possibleExchanges: ExchangeListItem[];
- }
-
-Get Withdrawal Details
-~~~~~~~~~~~~~~~~~~~~~~
-
-:Name: ``"getWithdrawalDetailsForAmount"``
-:Description:
- Get information about fees and exchange for a withdrawal of a given amount.
- Can be used for both bank-integrated and manual withdrawals.
-:Request:
- .. ts:def:: WithdrawalDetailsRequest
-
- interface WithdrawalDetailsRequest {
- exchangeBaseUrl: string;
- amount: Amount;
- }
-:Response:
- .. ts:def:: WithdrawalDetails
-
- interface WithdrawalDetails {
- // Did the user accept the current version of the exchange's terms of service?
- tosAccepted: boolean;
-
- // Amount that will be transferred to the exchange.
- amountRaw: Amount;
-
- // Amount that will be added to the user's wallet balance.
- amountEffective: Amount;
- }
-
-Accept Bank-integrated Withdrawal
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-:Name: ``"acceptWithdrawal"``
-:Description:
- Accept a bank-integrated withdrawal, where the bank transfers funds automatically.
-:Request:
- .. ts:def:: GetManualWithdrawalDetailsRequest
-
- interface AcceptWithdrawalRequest {
- talerWithdrawUri: string;
- exchangeBaseUrl: string;
- }
-:Response:
- .. ts:def:: AcceptWithdrawalResponse
-
- interface AcceptWithdrawalResponse {
- // a URL for user initiated confirmation.
- bankConfirmationUrl?: string;
- }
-
-Accept Manual Withdrawal
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-:Name: ``"acceptManualWithdrawal"``
-:Description:
- Accept a manual withdrawal, where the user has to transfer funds manually.
-:Request:
- .. ts:def:: AcceptManualWithdrawalRequest
-
- interface AcceptManualWithdrawalRequest {
- exchangeBaseUrl: string;
- amount: Amount;
- }
-:Response:
- .. ts:def:: AcceptManualWithdrawalResponse
-
- interface AcceptManualWithdrawalResponse {
- // Payto URIs to fund the withdrawal,
- // with amount and message provided.
- exchangePaytoUris: string[];
- }
-
-Deposits
---------
-
-Deposits are direct payments into a payment target (given via
-a payto URI). They don't involve a merchant.
-
-:Name: ``"createDepositGroup"``
-:Description:
- Deposit funds directly into a payment target.
-:Request:
- .. ts:def:: CreateDepositGroupRequest
-
- interface CreateDepositGroupRequest {
- depositPaytoUri: string;
- amount: Amount;
- }
-:Response:
- .. ts:def:: CreateDepositGroupResponse
-
- interface CreateDepositGroupResponse {
- depositGroupId: string;
- }
-
-
-Payments
---------
-
-Prepare Pay
-~~~~~~~~~~~
-
-:Name: ``"preparePay"``
-:Description:
- Fetch information about a payment request from a merchant.
-:Request:
- .. ts:def:: PreparePayRequest
-
- interface PreparePayRequest {
- talerPayUri: string;
- }
-:Response:
- .. ts:def:: PreparePayResponse
-
- type PreparePayResponse =
- | PreparePayPaymentPossibleResponse
- | PreparePayAlreadyConfirmedResponse
- | PreparePayInsufficientBalanceResponse;
-
- .. ts:def:: PreparePayPaymentPossibleResponse
-
- interface PreparePayPaymentPossibleResponse {
- status: "payment-possible";
-
- proposalId: string;
-
- // Verbatim contract terms as generated by the merchant.
- contractTerms: ContractTerms;
-
- // Amount that the merchant is asking for.
- amountRaw: Amount;
-
- // Amount that will effectively be subtracted from the wallet's
- // balance when accepting this proposal.
- amountEffective: Amount;
- }
-
- .. ts:def:: PreparePayInsufficientBalanceResponse
-
- interface PreparePayInsufficientBalanceResponse {
- status: "insufficient-balance";
-
- proposalId: string;
-
- // Amount that the merchant is asking for.
- amountRaw: Amount;
-
- // Verbatim contract terms as generated by the merchant.
- contractTerms: ContractTerms;
- }
-
- .. ts:def:: PreparePayAlreadyConfirmedResponse
-
- interface PreparePayAlreadyConfirmedResponse {
- status: "already-confirmed";
-
- proposalId: string;
-
- // Did the payment succeed?
- paid: boolean;
-
- // Amount that the merchant is asking for.
- amountRaw: Amount;
-
- // Amount that will be subtracted from the wallet balance
- amountEffective: Amount;
-
- // Verbatim contract terms as generated by the merchant.
- contractTerms: ContractTerms;
- }
-
-
-Confirm Payment
-~~~~~~~~~~~~~~~
-
-:Name: ``"confirmPay"``
-:Description:
- Confirm making a payment.
-
-:Request:
- .. ts:def:: GetManualWithdrawalDetailsRequest
-
- interface ConfirmPayRequest {
- proposalId: string;
- }
-:Response:
- .. ts:def:: ConfirmPayResultDone
-
- interface ConfirmPayResultDone {
- type: "done";
-
- contractTerms: ContractTerms;
- }
-
- .. ts:def:: ConfirmPayResultPending
-
- // Payment was marked as confirmed,
- // but the attempt(s) to pay were not successful yet.
- interface ConfirmPayPending {
- type: "pending";
-
- lastError: TransactionError;
- }
-
- .. ts:def:: ConfirmPayResult
-
- type ConfirmPayResult =
- | ConfirmPayResultDone;
- | ConfirmPayResultPending;
-
-Abort Failed Payment
-~~~~~~~~~~~~~~~~~~~~
-
-:Name: ``"abortFailedPayWithRefund"``
-:Description:
- Abort a failed payment and try to get a refund for the
- partially paid amount.
-:Request:
- .. ts:def:: AbortPayWithRefundRequest
-
- export interface AbortPayWithRefundRequest {
- proposalId: string;
- }
-:Response:
- On success, the response is an empty object.
-
-Tipping API Calls
------------------
-
-Preparing a tip
-~~~~~~~~~~~~~~~
-
-:Name: ``"prepareTip"``
-:Description:
- Prepare to accept a tip based in a ``taler://tip`` URI.
-:Request:
- .. ts:def:: PrepareTipRequest
-
- interface PrepareTipRequest {
- talerTipUri: string;
- }
-:Response:
- .. ts:def:: PrepareTipResult
-
- interface PrepareTipResult {
- // Unique ID for the tip assigned by the wallet.
- // Typically different from the merchant-generated tip ID.
- walletTipId: string;
-
- // Has the tip already been accepted?
- accepted: boolean;
- tipAmountRaw: Amount;
- tipAmountEffective: Amount;
- exchangeBaseUrl: string;
- expirationTimestamp: Timestamp;
- }
-
-
-Accepting a tip
-~~~~~~~~~~~~~~~
-
-:Name: ``"acceptTip"``
-:Description:
- Prepare to accept a tip based in a ``taler://tip`` URI.
-:Request:
- .. ts:def:: AcceptTipRequest
-
- interface AcceptTipRequest {
- walletTipId: string;
- }
-:Response:
- On success, the response is an empty object.
-
-Testing API calls
------------------
-
-The following API calls are useful for testing.
-
-Withdraw balance from the TESTKUDOS environment
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-:Name: ``"withdrawTestkudos"``
-:Description:
- Withdraw a balance from the ``TESTKUDOS`` environment.
-:Request:
- The request parameters are ignored.
-:Response:
- On success, the response is an empty object.
-
-Withdraw balance from a test environment
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-:Name: ``"withdrawTestBalance"``
-:Description:
- Withdraw a balance from a test environment.
-:Request:
- .. ts:def:: WithdrawTestBalanceRequest
-
- interface WithdrawTestBalanceRequest {
- amount: string;
- bankBaseUrl: string;
- exchangeBaseUrl: string;
- }
-:Response:
- On success, the response is an empty object.
-
-Run integration test
-~~~~~~~~~~~~~~~~~~~~
-
-:Name: ``"runIntegrationTest"``
-:Description:
- Run a basic integration test that does a withdrawal, payment,
- refund and again a payment. Useful to generate test data
- in the integration tests of other components.
-:Request:
- .. ts:def:: IntegrationTestArgs
-
- interface IntegrationTestArgs {
- exchangeBaseUrl: string;
- bankBaseUrl: string;
- merchantBaseUrl: string;
- merchantApiKey: string;
- amountToWithdraw: string;
- amountToSpend: string;
- }
-:Response:
- On success, the response is an empty object.
-
-Make a test payment
-~~~~~~~~~~~~~~~~~~~
-
-:Name: ``"testPay"``
-:Description:
- Make a test payment with existing funds.
-:Request:
- .. ts:def:: TestPayArgs
-
- interface TestPayArgs {
- merchantBaseUrl: string;
- merchantApiKey: string;
- amount: string;
- summary: string;
- }
-
-
-Dump all coins to JSON
-~~~~~~~~~~~~~~~~~~~~~~
-
-:Name: ``"dumpCoins"``
-:Description:
- Make a test payment with existing funds.
-:Request:
- The request object is ignored.
-:Response:
- .. code:: ts
-
- interface CoinDumpJson {
- coins: Array<{
- /**
- * The coin's denomination's public key.
- */
- denom_pub: string;
- /**
- * Hash of denom_pub.
- */
- denom_pub_hash: string;
- /**
- * Value of the denomination (without any fees).
- */
- denom_value: string;
- /**
- * Public key of the coin.
- */
- coin_pub: string;
- /**
- * Base URL of the exchange for the coin.
- */
- exchange_base_url: string;
- /**
- * Remaining value on the coin, to the knowledge of
- * the wallet.
- */
- remaining_value: string;
- /**
- * Public key of the parent coin.
- * Only present if this coin was obtained via refreshing.
- */
- refresh_parent_coin_pub: string | undefined;
- /**
- * Public key of the reserve for this coin.
- * Only present if this coin was obtained via refreshing.
- */
- withdrawal_reserve_pub: string | undefined;
- /**
- * Is the coin suspended?
- * Suspended coins are not considered for payments.
- */
- coin_suspended: boolean;
- }>;
- }
-
-
-Suspend/unsuspend a coin
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-A suspended coin will not be used by the wallet for payments.
-This functionality is only used for testing.
-
-:Name: ``"setCoinSuspended"``
-:Description:
- Make a test payment with existing funds.
-:Request:
- .. ts:def:: SetCoinSuspendedRequest
-
- interface SetCoinSuspendedRequest {
- coinPub: string;
- suspended: boolean;
- }
-:Request:
- On success, the response is an empty object.
-
-Global Errors
--------------
-
-* Backup/Sync/Anastasis failed
-* refresh after pay failed for multiple attempts
- (depending on online status)
-* scheduled refresh (to avoid expiration) failed
-* general recoups (?)
-* failed recoup
-* (maybe) fatal errors during withdrawal
-* pending refund failed permanently (?)
-
Integration Tests
=================
@@ -1205,7 +498,6 @@ Things we still need tests for:
Or when the merchant is not reachable? Or the bank?
This can be tested by temporarily killing those services.
* How does the wallet deal with processing the same ``taler://(pay|withdraw)`` URI twice?
-* Test tipping (accepting/refusing a tip)
* Test refunds
* Test for :ref:`session-based payments <repurchase>`
* Test case for auto-refunds
diff --git a/wallet/wallet-core.md b/wallet/wallet-core.md
new file mode 100644
index 00000000..8c600081
--- /dev/null
+++ b/wallet/wallet-core.md
@@ -0,0 +1,4105 @@
+# Wallet-Core API Documentation
+This file is auto-generated from [wallet-core](https://git.taler.net/wallet-core.git/tree/packages/taler-wallet-core/src/wallet-api-types.ts).
+## Overview
+### Unknown Group
+* [InitWalletOp](#initwalletop)
+* [SetWalletRunConfigOp](#setwalletrunconfigop)
+* [GetVersionOp](#getversionop)
+### Basic Wallet Information
+* [GetBalancesOp](#getbalancesop)
+* [GetBalancesDetailOp](#getbalancesdetailop)
+* [GetPlanForOperationOp](#getplanforoperationop)
+* [ConvertDepositAmountOp](#convertdepositamountop)
+* [GetMaxDepositAmountOp](#getmaxdepositamountop)
+* [ConvertPeerPushAmountOp](#convertpeerpushamountop)
+* [GetMaxPeerPushAmountOp](#getmaxpeerpushamountop)
+* [ConvertWithdrawalAmountOp](#convertwithdrawalamountop)
+### Managing Transactions
+* [GetTransactionsOp](#gettransactionsop)
+* [ListAssociatedRefreshesOp](#listassociatedrefreshesop)
+* [TestingGetSampleTransactionsOp](#testinggetsampletransactionsop)
+* [GetTransactionByIdOp](#gettransactionbyidop)
+* [GetWithdrawalTransactionByUriOp](#getwithdrawaltransactionbyuriop)
+* [RetryPendingNowOp](#retrypendingnowop)
+* [DeleteTransactionOp](#deletetransactionop)
+* [RetryTransactionOp](#retrytransactionop)
+* [AbortTransactionOp](#aborttransactionop)
+* [FailTransactionOp](#failtransactionop)
+* [SuspendTransactionOp](#suspendtransactionop)
+* [ResumeTransactionOp](#resumetransactionop)
+### Withdrawals
+* [GetWithdrawalDetailsForAmountOp](#getwithdrawaldetailsforamountop)
+* [GetWithdrawalDetailsForUriOp](#getwithdrawaldetailsforuriop)
+* [AcceptBankIntegratedWithdrawalOp](#acceptbankintegratedwithdrawalop)
+* [AcceptManualWithdrawalOp](#acceptmanualwithdrawalop)
+### Merchant Payments
+* [PreparePayForUriOp](#preparepayforuriop)
+* [SharePaymentOp](#sharepaymentop)
+* [PreparePayForTemplateOp](#preparepayfortemplateop)
+* [GetContractTermsDetailsOp](#getcontracttermsdetailsop)
+* [ConfirmPayOp](#confirmpayop)
+* [StartRefundQueryForUriOp](#startrefundqueryforuriop)
+* [StartRefundQueryOp](#startrefundqueryop)
+### Global Currency management
+* [ListGlobalCurrencyAuditorsOp](#listglobalcurrencyauditorsop)
+* [ListGlobalCurrencyExchangesOp](#listglobalcurrencyexchangesop)
+* [AddGlobalCurrencyExchangeOp](#addglobalcurrencyexchangeop)
+* [AddGlobalCurrencyAuditorOp](#addglobalcurrencyauditorop)
+* [RemoveGlobalCurrencyExchangeOp](#removeglobalcurrencyexchangeop)
+* [RemoveGlobalCurrencyAuditorOp](#removeglobalcurrencyauditorop)
+### Exchange Management
+* [ListExchangesOp](#listexchangesop)
+* [ListExchangesForScopedCurrencyOp](#listexchangesforscopedcurrencyop)
+* [PrepareWithdrawExchangeOp](#preparewithdrawexchangeop)
+* [AddExchangeOp](#addexchangeop)
+* [UpdateExchangeEntryOp](#updateexchangeentryop)
+* [ListKnownBankAccountsOp](#listknownbankaccountsop)
+* [AddKnownBankAccountsOp](#addknownbankaccountsop)
+* [ForgetKnownBankAccountsOp](#forgetknownbankaccountsop)
+* [SetExchangeTosAcceptedOp](#setexchangetosacceptedop)
+* [SetExchangeTosForgottenOp](#setexchangetosforgottenop)
+* [GetExchangeTosOp](#getexchangetosop)
+* [GetExchangeDetailedInfoOp](#getexchangedetailedinfoop)
+* [GetExchangeEntryByUrlOp](#getexchangeentrybyurlop)
+* [GetExchangeResourcesOp](#getexchangeresourcesop)
+* [DeleteExchangeOp](#deleteexchangeop)
+* [GetCurrencySpecificationOp](#getcurrencyspecificationop)
+### Deposits
+* [GenerateDepositGroupTxIdOp](#generatedepositgrouptxidop)
+* [CreateDepositGroupOp](#createdepositgroupop)
+* [PrepareDepositOp](#preparedepositop)
+### Backups
+* [ExportBackupRecoveryOp](#exportbackuprecoveryop)
+* [ImportBackupRecoveryOp](#importbackuprecoveryop)
+* [RunBackupCycleOp](#runbackupcycleop)
+* [ExportBackupOp](#exportbackupop)
+* [AddBackupProviderOp](#addbackupproviderop)
+* [RemoveBackupProviderOp](#removebackupproviderop)
+* [GetBackupInfoOp](#getbackupinfoop)
+* [SetWalletDeviceIdOp](#setwalletdeviceidop)
+* [ListStoredBackupsOp](#liststoredbackupsop)
+* [CreateStoredBackupsOp](#createstoredbackupsop)
+* [RecoverStoredBackupsOp](#recoverstoredbackupsop)
+* [DeleteStoredBackupOp](#deletestoredbackupop)
+### Peer Payments
+* [CheckPeerPushDebitOp](#checkpeerpushdebitop)
+* [InitiatePeerPushDebitOp](#initiatepeerpushdebitop)
+* [PreparePeerPushCreditOp](#preparepeerpushcreditop)
+* [ConfirmPeerPushCreditOp](#confirmpeerpushcreditop)
+* [CheckPeerPullCreditOp](#checkpeerpullcreditop)
+* [InitiatePeerPullCreditOp](#initiatepeerpullcreditop)
+* [PreparePeerPullDebitOp](#preparepeerpulldebitop)
+* [ConfirmPeerPullDebitOp](#confirmpeerpulldebitop)
+### Data Validation
+* [ValidateIbanOp](#validateibanop)
+### Database Management
+* [ExportDbOp](#exportdbop)
+* [ImportDbOp](#importdbop)
+* [ClearDbOp](#cleardbop)
+* [RecycleOp](#recycleop)
+### Testing and Debugging
+* [ApplyDevExperimentOp](#applydevexperimentop)
+* [RunIntegrationTestOp](#runintegrationtestop)
+* [RunIntegrationTestV2Op](#runintegrationtestv2op)
+* [TestCryptoOp](#testcryptoop)
+* [WithdrawTestBalanceOp](#withdrawtestbalanceop)
+* [WithdrawTestkudosOp](#withdrawtestkudosop)
+* [TestPayOp](#testpayop)
+* [GetPendingTasksOp](#getpendingtasksop)
+* [GetActiveTasksOp](#getactivetasksop)
+* [DumpCoinsOp](#dumpcoinsop)
+* [TestingSetTimetravelOp](#testingsettimetravelop)
+* [TestingListTasksForTransactionOp](#testinglisttasksfortransactionop)
+* [TestingWaitTransactionsFinalOp](#testingwaittransactionsfinalop)
+* [TestingWaitRefreshesFinalOp](#testingwaitrefreshesfinalop)
+* [TestingWaitTransactionStateOp](#testingwaittransactionstateop)
+* [TestingPingOp](#testingpingop)
+* [TestingGetDenomStatsOp](#testinggetdenomstatsop)
+* [SetCoinSuspendedOp](#setcoinsuspendedop)
+* [ForceRefreshOp](#forcerefreshop)
+## Operation Reference
+### InitWalletOp
+```typescript
+/**
+ * Initialize wallet-core.
+ *
+ * Must be the first request made to wallet-core.
+ */
+export type InitWalletOp = {
+ op: WalletApiOperation.InitWallet;
+ request: InitRequest;
+ response: InitResponse;
+};
+// InitWallet = "initWallet"
+
+```
+
+### SetWalletRunConfigOp
+```typescript
+/**
+ * Change the configuration of wallet-core.
+ *
+ * Currently an alias for the initWallet request.
+ */
+export type SetWalletRunConfigOp = {
+ op: WalletApiOperation.SetWalletRunConfig;
+ request: InitRequest;
+ response: InitResponse;
+};
+// SetWalletRunConfig = "setWalletRunConfig"
+
+```
+
+### GetVersionOp
+```typescript
+export type GetVersionOp = {
+ op: WalletApiOperation.GetVersion;
+ request: EmptyObject;
+ response: WalletCoreVersion;
+};
+// GetVersion = "getVersion"
+
+```
+
+### GetBalancesOp
+```typescript
+/**
+ * Get current wallet balance.
+ */
+export type GetBalancesOp = {
+ op: WalletApiOperation.GetBalances;
+ request: EmptyObject;
+ response: BalancesResponse;
+};
+// GetBalances = "getBalances"
+
+```
+```typescript
+export interface BalancesResponse {
+ balances: WalletBalance[];
+}
+
+```
+```typescript
+export interface WalletBalance {
+ scopeInfo: ScopeInfo;
+ available: AmountString;
+ pendingIncoming: AmountString;
+ pendingOutgoing: AmountString;
+ /**
+ * Does the balance for this currency have a pending
+ * transaction?
+ *
+ * @deprecated use flags and pendingIncoming/pendingOutgoing instead
+ */
+ hasPendingTransactions: boolean;
+ /**
+ * Is there a transaction that requires user input?
+ *
+ * @deprecated use flags instead
+ */
+ requiresUserInput: boolean;
+ flags: BalanceFlag[];
+}
+
+```
+```typescript
+export declare enum BalanceFlag {
+ IncomingKyc = "incoming-kyc",
+ IncomingAml = "incoming-aml",
+ IncomingConfirmation = "incoming-confirmation",
+ OutgoingKyc = "outgoing-kyc",
+}
+
+```
+
+### GetBalancesDetailOp
+```typescript
+export type GetBalancesDetailOp = {
+ op: WalletApiOperation.GetBalanceDetail;
+ request: GetBalanceDetailRequest;
+ response: PaymentBalanceDetails;
+};
+// GetBalanceDetail = "getBalanceDetail"
+
+```
+```typescript
+export interface GetBalanceDetailRequest {
+ currency: string;
+}
+
+```
+```typescript
+export interface PaymentBalanceDetails {
+ /**
+ * Balance of type "available" (see balance.ts for definition).
+ */
+ balanceAvailable: AmountJson;
+ /**
+ * Balance of type "material" (see balance.ts for definition).
+ */
+ balanceMaterial: AmountJson;
+ /**
+ * Balance of type "age-acceptable" (see balance.ts for definition).
+ */
+ balanceAgeAcceptable: AmountJson;
+ /**
+ * Balance of type "merchant-acceptable" (see balance.ts for definition).
+ */
+ balanceReceiverAcceptable: AmountJson;
+ /**
+ * Balance of type "merchant-depositable" (see balance.ts for definition).
+ */
+ balanceReceiverDepositable: AmountJson;
+ /**
+ * Balance that's depositable with the exchange.
+ * This balance is reduced by the exchange's debit restrictions
+ * and wire fee configuration.
+ */
+ balanceExchangeDepositable: AmountJson;
+ maxEffectiveSpendAmount: AmountJson;
+}
+
+```
+```typescript
+/**
+ * Non-negative financial amount. Fractional values are expressed as multiples
+ * of 1e-8.
+ */
+export interface AmountJson {
+ /**
+ * Value, must be an integer.
+ */
+ readonly value: number;
+ /**
+ * Fraction, must be an integer. Represent 1/1e8 of a unit.
+ */
+ readonly fraction: number;
+ /**
+ * Currency of the amount.
+ */
+ readonly currency: string;
+}
+
+```
+
+### GetPlanForOperationOp
+```typescript
+export type GetPlanForOperationOp = {
+ op: WalletApiOperation.GetPlanForOperation;
+ request: GetPlanForOperationRequest;
+ response: GetPlanForOperationResponse;
+};
+// GetPlanForOperation = "getPlanForOperation"
+
+```
+```typescript
+export type GetPlanForOperationRequest =
+ | GetPlanForWithdrawRequest
+ | GetPlanForDepositRequest;
+
+```
+```typescript
+interface GetPlanForWithdrawRequest extends GetPlanForWalletInitiatedOperation {
+ type: TransactionType.Withdrawal;
+ exchangeUrl?: string;
+}
+
+```
+```typescript
+interface GetPlanForWalletInitiatedOperation {
+ instructedAmount: AmountString;
+ mode: TransactionAmountMode;
+}
+
+```
+```typescript
+interface GetPlanForDepositRequest extends GetPlanForWalletInitiatedOperation {
+ type: TransactionType.Deposit;
+ account: string;
+}
+
+```
+```typescript
+export interface GetPlanForOperationResponse {
+ effectiveAmount: AmountString;
+ rawAmount: AmountString;
+ counterPartyAmount?: AmountString;
+ details: any;
+}
+
+```
+
+### ConvertDepositAmountOp
+```typescript
+export type ConvertDepositAmountOp = {
+ op: WalletApiOperation.ConvertDepositAmount;
+ request: ConvertAmountRequest;
+ response: AmountResponse;
+};
+// ConvertDepositAmount = "ConvertDepositAmount"
+
+```
+
+### GetMaxDepositAmountOp
+```typescript
+export type GetMaxDepositAmountOp = {
+ op: WalletApiOperation.GetMaxDepositAmount;
+ request: GetAmountRequest;
+ response: AmountResponse;
+};
+// GetMaxDepositAmount = "GetMaxDepositAmount"
+
+```
+
+### ConvertPeerPushAmountOp
+```typescript
+export type ConvertPeerPushAmountOp = {
+ op: WalletApiOperation.ConvertPeerPushAmount;
+ request: ConvertAmountRequest;
+ response: AmountResponse;
+};
+// ConvertPeerPushAmount = "ConvertPeerPushAmount"
+
+```
+
+### GetMaxPeerPushAmountOp
+```typescript
+export type GetMaxPeerPushAmountOp = {
+ op: WalletApiOperation.GetMaxPeerPushAmount;
+ request: GetAmountRequest;
+ response: AmountResponse;
+};
+// GetMaxPeerPushAmount = "GetMaxPeerPushAmount"
+
+```
+
+### ConvertWithdrawalAmountOp
+```typescript
+export type ConvertWithdrawalAmountOp = {
+ op: WalletApiOperation.ConvertWithdrawalAmount;
+ request: ConvertAmountRequest;
+ response: AmountResponse;
+};
+// ConvertWithdrawalAmount = "ConvertWithdrawalAmount"
+
+```
+
+### GetTransactionsOp
+```typescript
+/**
+ * Get transactions.
+ */
+export type GetTransactionsOp = {
+ op: WalletApiOperation.GetTransactions;
+ request: TransactionsRequest;
+ response: TransactionsResponse;
+};
+// GetTransactions = "getTransactions"
+
+```
+```typescript
+export interface TransactionsRequest {
+ /**
+ * return only transactions in the given currency
+ *
+ * it will be removed in next release
+ *
+ * @deprecated use scopeInfo
+ */
+ currency?: string;
+ /**
+ * return only transactions in the given scopeInfo
+ */
+ scopeInfo?: ScopeInfo;
+ /**
+ * if present, results will be limited to transactions related to the given search string
+ */
+ search?: string;
+ /**
+ * Sort order of the transaction items.
+ * By default, items are sorted ascending by their
+ * main timestamp.
+ *
+ * ascending: ascending by timestamp, but pending transactions first
+ * descending: ascending by timestamp, but pending transactions first
+ * stable-ascending: ascending by timestamp, with pending transactions amidst other transactions
+ * (stable in the sense of: pending transactions don't jump around)
+ */
+ sort?: "ascending" | "descending" | "stable-ascending";
+ /**
+ * If true, include all refreshes in the transactions list.
+ */
+ includeRefreshes?: boolean;
+ filterByState?: TransactionStateFilter;
+}
+
+```
+
+### ListAssociatedRefreshesOp
+```typescript
+/**
+ * List refresh transactions associated with another transaction.
+ */
+export type ListAssociatedRefreshesOp = {
+ op: WalletApiOperation.ListAssociatedRefreshes;
+ request: ListAssociatedRefreshesRequest;
+ response: ListAssociatedRefreshesResponse;
+};
+// ListAssociatedRefreshes = "listAssociatedRefreshes"
+
+```
+```typescript
+export interface ListAssociatedRefreshesRequest {
+ transactionId: string;
+}
+
+```
+```typescript
+export interface ListAssociatedRefreshesResponse {
+ transactionIds: string[];
+}
+
+```
+
+### TestingGetSampleTransactionsOp
+```typescript
+/**
+ * Get sample transactions.
+ */
+export type TestingGetSampleTransactionsOp = {
+ op: WalletApiOperation.TestingGetSampleTransactions;
+ request: EmptyObject;
+ response: TransactionsResponse;
+};
+// TestingGetSampleTransactions = "testingGetSampleTransactions"
+
+```
+
+### GetTransactionByIdOp
+```typescript
+export type GetTransactionByIdOp = {
+ op: WalletApiOperation.GetTransactionById;
+ request: TransactionByIdRequest;
+ response: Transaction;
+};
+// GetTransactionById = "getTransactionById"
+
+```
+```typescript
+export interface TransactionByIdRequest {
+ transactionId: string;
+}
+
+```
+
+### GetWithdrawalTransactionByUriOp
+```typescript
+export type GetWithdrawalTransactionByUriOp = {
+ op: WalletApiOperation.GetWithdrawalTransactionByUri;
+ request: WithdrawalTransactionByURIRequest;
+ response: TransactionWithdrawal | undefined;
+};
+// GetWithdrawalTransactionByUri = "getWithdrawalTransactionByUri"
+
+```
+```typescript
+export interface WithdrawalTransactionByURIRequest {
+ talerWithdrawUri: string;
+}
+
+```
+
+### RetryPendingNowOp
+```typescript
+export type RetryPendingNowOp = {
+ op: WalletApiOperation.RetryPendingNow;
+ request: EmptyObject;
+ response: EmptyObject;
+};
+// RetryPendingNow = "retryPendingNow"
+
+```
+
+### DeleteTransactionOp
+```typescript
+/**
+ * Delete a transaction locally in the wallet.
+ */
+export type DeleteTransactionOp = {
+ op: WalletApiOperation.DeleteTransaction;
+ request: DeleteTransactionRequest;
+ response: EmptyObject;
+};
+// DeleteTransaction = "deleteTransaction"
+
+```
+```typescript
+export interface DeleteTransactionRequest {
+ transactionId: TransactionIdStr;
+}
+
+```
+
+### RetryTransactionOp
+```typescript
+/**
+ * Immediately retry a transaction.
+ */
+export type RetryTransactionOp = {
+ op: WalletApiOperation.RetryTransaction;
+ request: RetryTransactionRequest;
+ response: EmptyObject;
+};
+// RetryTransaction = "retryTransaction"
+
+```
+```typescript
+export interface RetryTransactionRequest {
+ transactionId: TransactionIdStr;
+}
+
+```
+
+### AbortTransactionOp
+```typescript
+/**
+ * Abort a transaction
+ *
+ * For payment transactions, it puts the payment into an "aborting" state.
+ */
+export type AbortTransactionOp = {
+ op: WalletApiOperation.AbortTransaction;
+ request: AbortTransactionRequest;
+ response: EmptyObject;
+};
+// AbortTransaction = "abortTransaction"
+
+```
+
+### FailTransactionOp
+```typescript
+/**
+ * Cancel aborting a transaction
+ *
+ * For payment transactions, it puts the payment into an "aborting" state.
+ */
+export type FailTransactionOp = {
+ op: WalletApiOperation.FailTransaction;
+ request: FailTransactionRequest;
+ response: EmptyObject;
+};
+// FailTransaction = "failTransaction"
+
+```
+```typescript
+export interface FailTransactionRequest {
+ transactionId: TransactionIdStr;
+}
+
+```
+
+### SuspendTransactionOp
+```typescript
+/**
+ * Suspend a transaction
+ */
+export type SuspendTransactionOp = {
+ op: WalletApiOperation.SuspendTransaction;
+ request: AbortTransactionRequest;
+ response: EmptyObject;
+};
+// SuspendTransaction = "suspendTransaction"
+
+```
+
+### ResumeTransactionOp
+```typescript
+/**
+ * Resume a transaction
+ */
+export type ResumeTransactionOp = {
+ op: WalletApiOperation.ResumeTransaction;
+ request: AbortTransactionRequest;
+ response: EmptyObject;
+};
+// ResumeTransaction = "resumeTransaction"
+
+```
+
+### GetWithdrawalDetailsForAmountOp
+```typescript
+/**
+ * Get details for withdrawing a particular amount (manual withdrawal).
+ */
+export type GetWithdrawalDetailsForAmountOp = {
+ op: WalletApiOperation.GetWithdrawalDetailsForAmount;
+ request: GetWithdrawalDetailsForAmountRequest;
+ response: WithdrawalDetailsForAmount;
+};
+// GetWithdrawalDetailsForAmount = "getWithdrawalDetailsForAmount"
+
+```
+```typescript
+export interface GetWithdrawalDetailsForAmountRequest {
+ exchangeBaseUrl: string;
+ amount: AmountString;
+ restrictAge?: number;
+}
+
+```
+```typescript
+export interface WithdrawalDetailsForAmount {
+ /**
+ * Did the user accept the current version of the exchange's
+ * terms of service?
+ *
+ * @deprecated the client should query the exchange entry instead
+ */
+ tosAccepted: boolean;
+ /**
+ * Amount that the user will transfer to the exchange.
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount that will be added to the user's wallet balance.
+ */
+ amountEffective: AmountString;
+ /**
+ * Number of coins that would be used for withdrawal.
+ *
+ * The UIs should warn if this number is too high (roughly at >100).
+ */
+ numCoins: number;
+ /**
+ * Ways to pay the exchange.
+ *
+ * @deprecated in favor of withdrawalAccountsList
+ */
+ paytoUris: string[];
+ /**
+ * Ways to pay the exchange, including accounts that require currency conversion.
+ */
+ withdrawalAccountsList: WithdrawalExchangeAccountDetails[];
+ /**
+ * If the exchange supports age-restricted coins it will return
+ * the array of ages.
+ */
+ ageRestrictionOptions?: number[];
+ /**
+ * Scope info of the currency withdrawn.
+ */
+ scopeInfo: ScopeInfo;
+}
+
+```
+
+### GetWithdrawalDetailsForUriOp
+```typescript
+/**
+ * Get details for withdrawing via a particular taler:// URI.
+ */
+export type GetWithdrawalDetailsForUriOp = {
+ op: WalletApiOperation.GetWithdrawalDetailsForUri;
+ request: GetWithdrawalDetailsForUriRequest;
+ response: WithdrawUriInfoResponse;
+};
+// GetWithdrawalDetailsForUri = "getWithdrawalDetailsForUri"
+
+```
+```typescript
+export interface GetWithdrawalDetailsForUriRequest {
+ talerWithdrawUri: string;
+ restrictAge?: number;
+ notifyChangeFromPendingTimeoutMs?: number;
+}
+
+```
+```typescript
+export interface WithdrawUriInfoResponse {
+ operationId: string;
+ status: WithdrawalOperationStatus;
+ confirmTransferUrl?: string;
+ amount: AmountString;
+ defaultExchangeBaseUrl?: string;
+ possibleExchanges: ExchangeListItem[];
+}
+
+```
+```typescript
+export type WithdrawalOperationStatus =
+ | "pending"
+ | "selected"
+ | "aborted"
+ | "confirmed";
+
+```
+
+### AcceptBankIntegratedWithdrawalOp
+```typescript
+/**
+ * Accept a bank-integrated withdrawal.
+ */
+export type AcceptBankIntegratedWithdrawalOp = {
+ op: WalletApiOperation.AcceptBankIntegratedWithdrawal;
+ request: AcceptBankIntegratedWithdrawalRequest;
+ response: AcceptWithdrawalResponse;
+};
+// AcceptBankIntegratedWithdrawal = "acceptBankIntegratedWithdrawal"
+
+```
+```typescript
+export interface AcceptBankIntegratedWithdrawalRequest {
+ talerWithdrawUri: string;
+ exchangeBaseUrl: string;
+ forcedDenomSel?: ForcedDenomSel;
+ restrictAge?: number;
+}
+
+```
+```typescript
+export interface AcceptWithdrawalResponse {
+ reservePub: string;
+ confirmTransferUrl?: string;
+ transactionId: TransactionIdStr;
+}
+
+```
+
+### AcceptManualWithdrawalOp
+```typescript
+/**
+ * Create a manual withdrawal.
+ */
+export type AcceptManualWithdrawalOp = {
+ op: WalletApiOperation.AcceptManualWithdrawal;
+ request: AcceptManualWithdrawalRequest;
+ response: AcceptManualWithdrawalResult;
+};
+// AcceptManualWithdrawal = "acceptManualWithdrawal"
+
+```
+```typescript
+export interface AcceptManualWithdrawalRequest {
+ exchangeBaseUrl: string;
+ amount: AmountString;
+ restrictAge?: number;
+}
+
+```
+```typescript
+export interface AcceptManualWithdrawalResult {
+ /**
+ * Payto URIs that can be used to fund the withdrawal.
+ *
+ * @deprecated in favor of withdrawalAccountsList
+ */
+ exchangePaytoUris: string[];
+ /**
+ * Public key of the newly created reserve.
+ */
+ reservePub: string;
+ withdrawalAccountsList: WithdrawalExchangeAccountDetails[];
+ transactionId: TransactionIdStr;
+}
+
+```
+
+### PreparePayForUriOp
+```typescript
+/**
+ * Prepare to make a payment based on a taler://pay/ URI.
+ */
+export type PreparePayForUriOp = {
+ op: WalletApiOperation.PreparePayForUri;
+ request: PreparePayRequest;
+ response: PreparePayResult;
+};
+// PreparePayForUri = "preparePayForUri"
+
+```
+```typescript
+export interface PreparePayRequest {
+ talerPayUri: string;
+}
+
+```
+
+### SharePaymentOp
+```typescript
+export type SharePaymentOp = {
+ op: WalletApiOperation.SharePayment;
+ request: SharePaymentRequest;
+ response: SharePaymentResult;
+};
+// SharePayment = "sharePayment"
+
+```
+```typescript
+export interface SharePaymentRequest {
+ merchantBaseUrl: string;
+ orderId: string;
+}
+
+```
+```typescript
+export interface SharePaymentResult {
+ privatePayUri: string;
+}
+
+```
+
+### PreparePayForTemplateOp
+```typescript
+/**
+ * Prepare to make a payment based on a taler://pay-template/ URI.
+ */
+export type PreparePayForTemplateOp = {
+ op: WalletApiOperation.PreparePayForTemplate;
+ request: PreparePayTemplateRequest;
+ response: PreparePayResult;
+};
+// PreparePayForTemplate = "preparePayForTemplate"
+
+```
+```typescript
+export interface PreparePayTemplateRequest {
+ talerPayTemplateUri: string;
+ templateParams?: TemplateParams;
+}
+
+```
+
+### GetContractTermsDetailsOp
+```typescript
+export type GetContractTermsDetailsOp = {
+ op: WalletApiOperation.GetContractTermsDetails;
+ request: GetContractTermsDetailsRequest;
+ response: WalletContractData;
+};
+// GetContractTermsDetails = "getContractTermsDetails"
+
+```
+```typescript
+export interface GetContractTermsDetailsRequest {
+ proposalId: string;
+}
+
+```
+```typescript
+/**
+ * Data extracted from the contract terms that is relevant for payment
+ * processing in the wallet.
+ */
+export interface WalletContractData {
+ /**
+ * Fulfillment URL, or the empty string if the order has no fulfillment URL.
+ *
+ * Stored as a non-nullable string as we use this field for IndexedDB indexing.
+ */
+ fulfillmentUrl: string;
+ contractTermsHash: string;
+ fulfillmentMessage?: string;
+ fulfillmentMessageI18n?: InternationalizedString;
+ merchantSig: string;
+ merchantPub: string;
+ merchant: MerchantInfo;
+ amount: AmountString;
+ orderId: string;
+ merchantBaseUrl: string;
+ summary: string;
+ summaryI18n:
+ | {
+ [lang_tag: string]: string;
+ }
+ | undefined;
+ autoRefund: TalerProtocolDuration | undefined;
+ payDeadline: TalerProtocolTimestamp;
+ refundDeadline: TalerProtocolTimestamp;
+ allowedExchanges: AllowedExchangeInfo[];
+ timestamp: TalerProtocolTimestamp;
+ wireMethod: string;
+ wireInfoHash: string;
+ maxDepositFee: AmountString;
+ minimumAge?: number;
+}
+
+```
+```typescript
+export interface AllowedExchangeInfo {
+ exchangeBaseUrl: string;
+ exchangePub: string;
+}
+
+```
+
+### ConfirmPayOp
+```typescript
+/**
+ * Confirm a payment that was previously prepared with
+ * {@link PreparePayForUriOp}
+ */
+export type ConfirmPayOp = {
+ op: WalletApiOperation.ConfirmPay;
+ request: ConfirmPayRequest;
+ response: ConfirmPayResult;
+};
+// ConfirmPay = "confirmPay"
+
+```
+```typescript
+export interface ConfirmPayRequest {
+ /**
+ * @deprecated use transactionId instead
+ */
+ proposalId?: string;
+ transactionId?: TransactionIdStr;
+ sessionId?: string;
+ forcedCoinSel?: ForcedCoinSel;
+}
+
+```
+```typescript
+export type ConfirmPayResult = ConfirmPayResultDone | ConfirmPayResultPending;
+
+```
+```typescript
+/**
+ * Result for confirmPay
+ */
+export interface ConfirmPayResultDone {
+ type: ConfirmPayResultType.Done;
+ contractTerms: MerchantContractTerms;
+ transactionId: TransactionIdStr;
+}
+
+```
+```typescript
+export interface ConfirmPayResultPending {
+ type: ConfirmPayResultType.Pending;
+ transactionId: TransactionIdStr;
+ lastError: TalerErrorDetail | undefined;
+}
+
+```
+
+### StartRefundQueryForUriOp
+```typescript
+/**
+ * Check for a refund based on a taler://refund URI.
+ */
+export type StartRefundQueryForUriOp = {
+ op: WalletApiOperation.StartRefundQueryForUri;
+ request: PrepareRefundRequest;
+ response: StartRefundQueryForUriResponse;
+};
+// StartRefundQueryForUri = "startRefundQueryForUri"
+
+```
+```typescript
+export interface PrepareRefundRequest {
+ talerRefundUri: string;
+}
+
+```
+```typescript
+export interface StartRefundQueryForUriResponse {
+ /**
+ * Transaction id of the *payment* where the refund query was started.
+ */
+ transactionId: TransactionIdStr;
+}
+
+```
+
+### StartRefundQueryOp
+```typescript
+export type StartRefundQueryOp = {
+ op: WalletApiOperation.StartRefundQuery;
+ request: StartRefundQueryRequest;
+ response: EmptyObject;
+};
+// StartRefundQuery = "startRefundQuery"
+
+```
+```typescript
+export interface StartRefundQueryRequest {
+ transactionId: TransactionIdStr;
+}
+
+```
+
+### ListGlobalCurrencyAuditorsOp
+```typescript
+export type ListGlobalCurrencyAuditorsOp = {
+ op: WalletApiOperation.ListGlobalCurrencyAuditors;
+ request: EmptyObject;
+ response: ListGlobalCurrencyAuditorsResponse;
+};
+// ListGlobalCurrencyAuditors = "listGlobalCurrencyAuditors"
+
+```
+```typescript
+export interface ListGlobalCurrencyAuditorsResponse {
+ auditors: {
+ currency: string;
+ auditorBaseUrl: string;
+ auditorPub: string;
+ }[];
+}
+
+```
+
+### ListGlobalCurrencyExchangesOp
+```typescript
+export type ListGlobalCurrencyExchangesOp = {
+ op: WalletApiOperation.ListGlobalCurrencyExchanges;
+ request: EmptyObject;
+ response: ListGlobalCurrencyExchangesResponse;
+};
+// ListGlobalCurrencyExchanges = "listGlobalCurrencyExchanges"
+
+```
+```typescript
+export interface ListGlobalCurrencyExchangesResponse {
+ exchanges: {
+ currency: string;
+ exchangeBaseUrl: string;
+ exchangeMasterPub: string;
+ }[];
+}
+
+```
+
+### AddGlobalCurrencyExchangeOp
+```typescript
+export type AddGlobalCurrencyExchangeOp = {
+ op: WalletApiOperation.AddGlobalCurrencyExchange;
+ request: AddGlobalCurrencyExchangeRequest;
+ response: EmptyObject;
+};
+// AddGlobalCurrencyExchange = "addGlobalCurrencyExchange"
+
+```
+```typescript
+export interface AddGlobalCurrencyExchangeRequest {
+ currency: string;
+ exchangeBaseUrl: string;
+ exchangeMasterPub: string;
+}
+
+```
+
+### AddGlobalCurrencyAuditorOp
+```typescript
+export type AddGlobalCurrencyAuditorOp = {
+ op: WalletApiOperation.AddGlobalCurrencyAuditor;
+ request: AddGlobalCurrencyAuditorRequest;
+ response: EmptyObject;
+};
+// AddGlobalCurrencyAuditor = "addGlobalCurrencyAuditor"
+
+```
+```typescript
+export interface AddGlobalCurrencyAuditorRequest {
+ currency: string;
+ auditorBaseUrl: string;
+ auditorPub: string;
+}
+
+```
+
+### RemoveGlobalCurrencyExchangeOp
+```typescript
+export type RemoveGlobalCurrencyExchangeOp = {
+ op: WalletApiOperation.RemoveGlobalCurrencyExchange;
+ request: RemoveGlobalCurrencyExchangeRequest;
+ response: EmptyObject;
+};
+// RemoveGlobalCurrencyExchange = "removeGlobalCurrencyExchange"
+
+```
+```typescript
+export interface RemoveGlobalCurrencyExchangeRequest {
+ currency: string;
+ exchangeBaseUrl: string;
+ exchangeMasterPub: string;
+}
+
+```
+
+### RemoveGlobalCurrencyAuditorOp
+```typescript
+export type RemoveGlobalCurrencyAuditorOp = {
+ op: WalletApiOperation.RemoveGlobalCurrencyAuditor;
+ request: RemoveGlobalCurrencyAuditorRequest;
+ response: EmptyObject;
+};
+// RemoveGlobalCurrencyAuditor = "removeGlobalCurrencyAuditor"
+
+```
+```typescript
+export interface RemoveGlobalCurrencyAuditorRequest {
+ currency: string;
+ auditorBaseUrl: string;
+ auditorPub: string;
+}
+
+```
+
+### ListExchangesOp
+```typescript
+/**
+ * List exchanges known to the wallet.
+ */
+export type ListExchangesOp = {
+ op: WalletApiOperation.ListExchanges;
+ request: EmptyObject;
+ response: ExchangesListResponse;
+};
+// ListExchanges = "listExchanges"
+
+```
+```typescript
+export interface ExchangesListResponse {
+ exchanges: ExchangeListItem[];
+}
+
+```
+
+### ListExchangesForScopedCurrencyOp
+```typescript
+/**
+ * List exchanges that are available for withdrawing a particular
+ * scoped currency.
+ */
+export type ListExchangesForScopedCurrencyOp = {
+ op: WalletApiOperation.ListExchangesForScopedCurrency;
+ request: ListExchangesForScopedCurrencyRequest;
+ response: ExchangesShortListResponse;
+};
+// ListExchangesForScopedCurrency = "listExchangesForScopedCurrency"
+
+```
+```typescript
+export interface ListExchangesForScopedCurrencyRequest {
+ scope: ScopeInfo;
+}
+
+```
+```typescript
+export interface ExchangesShortListResponse {
+ exchanges: ShortExchangeListItem[];
+}
+
+```
+```typescript
+export interface ShortExchangeListItem {
+ exchangeBaseUrl: string;
+}
+
+```
+
+### PrepareWithdrawExchangeOp
+```typescript
+/**
+ * Prepare for withdrawing via a taler://withdraw-exchange URI.
+ */
+export type PrepareWithdrawExchangeOp = {
+ op: WalletApiOperation.PrepareWithdrawExchange;
+ request: PrepareWithdrawExchangeRequest;
+ response: PrepareWithdrawExchangeResponse;
+};
+// PrepareWithdrawExchange = "prepareWithdrawExchange"
+
+```
+```typescript
+export interface PrepareWithdrawExchangeRequest {
+ /**
+ * A taler://withdraw-exchange URI.
+ */
+ talerUri: string;
+}
+
+```
+```typescript
+export interface PrepareWithdrawExchangeResponse {
+ /**
+ * Base URL of the exchange that already existed
+ * or was ephemerally added as an exchange entry to
+ * the wallet.
+ */
+ exchangeBaseUrl: string;
+ /**
+ * Amount from the taler://withdraw-exchange URI.
+ * Only present if specified in the URI.
+ */
+ amount?: AmountString;
+}
+
+```
+
+### AddExchangeOp
+```typescript
+/**
+ * Add / force-update an exchange.
+ */
+export type AddExchangeOp = {
+ op: WalletApiOperation.AddExchange;
+ request: AddExchangeRequest;
+ response: EmptyObject;
+};
+// AddExchange = "addExchange"
+
+```
+
+### UpdateExchangeEntryOp
+```typescript
+/**
+ * Update an exchange entry.
+ */
+export type UpdateExchangeEntryOp = {
+ op: WalletApiOperation.UpdateExchangeEntry;
+ request: UpdateExchangeEntryRequest;
+ response: EmptyObject;
+};
+// UpdateExchangeEntry = "updateExchangeEntry"
+
+```
+```typescript
+export interface UpdateExchangeEntryRequest {
+ exchangeBaseUrl: string;
+ force?: boolean;
+}
+
+```
+
+### ListKnownBankAccountsOp
+```typescript
+export type ListKnownBankAccountsOp = {
+ op: WalletApiOperation.ListKnownBankAccounts;
+ request: ListKnownBankAccountsRequest;
+ response: KnownBankAccounts;
+};
+// ListKnownBankAccounts = "listKnownBankAccounts"
+
+```
+```typescript
+export interface ListKnownBankAccountsRequest {
+ currency?: string;
+}
+
+```
+```typescript
+export interface KnownBankAccounts {
+ accounts: KnownBankAccountsInfo[];
+}
+
+```
+```typescript
+export interface KnownBankAccountsInfo {
+ uri: PaytoUri;
+ kyc_completed: boolean;
+ currency: string;
+ alias: string;
+}
+
+```
+```typescript
+export type PaytoUri =
+ | PaytoUriUnknown
+ | PaytoUriIBAN
+ | PaytoUriTalerBank
+ | PaytoUriBitcoin;
+
+```
+```typescript
+export interface PaytoUriUnknown extends PaytoUriGeneric {
+ isKnown: false;
+}
+
+```
+```typescript
+export interface PaytoUriGeneric {
+ targetType: PaytoType | string;
+ targetPath: string;
+ params: {
+ [name: string]: string;
+ };
+}
+
+```
+```typescript
+export type PaytoType = "iban" | "bitcoin" | "x-taler-bank";
+
+```
+```typescript
+export interface PaytoUriIBAN extends PaytoUriGeneric {
+ isKnown: true;
+ targetType: "iban";
+ iban: string;
+ bic?: string;
+}
+
+```
+```typescript
+export interface PaytoUriTalerBank extends PaytoUriGeneric {
+ isKnown: true;
+ targetType: "x-taler-bank";
+ host: string;
+ account: string;
+}
+
+```
+```typescript
+export interface PaytoUriBitcoin extends PaytoUriGeneric {
+ isKnown: true;
+ targetType: "bitcoin";
+ address: string;
+ segwitAddrs: Array<string>;
+}
+
+```
+
+### AddKnownBankAccountsOp
+```typescript
+export type AddKnownBankAccountsOp = {
+ op: WalletApiOperation.AddKnownBankAccounts;
+ request: AddKnownBankAccountsRequest;
+ response: EmptyObject;
+};
+// AddKnownBankAccounts = "addKnownBankAccounts"
+
+```
+```typescript
+export interface AddKnownBankAccountsRequest {
+ payto: string;
+ alias: string;
+ currency: string;
+}
+
+```
+
+### ForgetKnownBankAccountsOp
+```typescript
+export type ForgetKnownBankAccountsOp = {
+ op: WalletApiOperation.ForgetKnownBankAccounts;
+ request: ForgetKnownBankAccountsRequest;
+ response: EmptyObject;
+};
+// ForgetKnownBankAccounts = "forgetKnownBankAccounts"
+
+```
+```typescript
+export interface ForgetKnownBankAccountsRequest {
+ payto: string;
+}
+
+```
+
+### SetExchangeTosAcceptedOp
+```typescript
+/**
+ * Accept a particular version of the exchange terms of service.
+ */
+export type SetExchangeTosAcceptedOp = {
+ op: WalletApiOperation.SetExchangeTosAccepted;
+ request: AcceptExchangeTosRequest;
+ response: EmptyObject;
+};
+// SetExchangeTosAccepted = "setExchangeTosAccepted"
+
+```
+
+### SetExchangeTosForgottenOp
+```typescript
+/**
+ * Accept a particular version of the exchange terms of service.
+ */
+export type SetExchangeTosForgottenOp = {
+ op: WalletApiOperation.SetExchangeTosForgotten;
+ request: AcceptExchangeTosRequest;
+ response: EmptyObject;
+};
+// SetExchangeTosForgotten = "SetExchangeTosForgotten"
+
+```
+
+### GetExchangeTosOp
+```typescript
+/**
+ * Get the current terms of a service of an exchange.
+ */
+export type GetExchangeTosOp = {
+ op: WalletApiOperation.GetExchangeTos;
+ request: GetExchangeTosRequest;
+ response: GetExchangeTosResult;
+};
+// GetExchangeTos = "getExchangeTos"
+
+```
+```typescript
+export interface GetExchangeTosRequest {
+ exchangeBaseUrl: string;
+ acceptedFormat?: string[];
+ acceptLanguage?: string;
+}
+
+```
+```typescript
+export interface GetExchangeTosResult {
+ /**
+ * Markdown version of the current ToS.
+ */
+ content: string;
+ /**
+ * Version tag of the current ToS.
+ */
+ currentEtag: string;
+ /**
+ * Version tag of the last ToS that the user has accepted,
+ * if any.
+ */
+ acceptedEtag: string | undefined;
+ /**
+ * Accepted content type
+ */
+ contentType: string;
+ /**
+ * Language of the returned content.
+ *
+ * If missing, language is unknown.
+ */
+ contentLanguage: string | undefined;
+ /**
+ * Available languages as advertised by the exchange.
+ */
+ tosAvailableLanguages: string[];
+ tosStatus: ExchangeTosStatus;
+}
+
+```
+
+### GetExchangeDetailedInfoOp
+```typescript
+/**
+ * Get the current terms of a service of an exchange.
+ */
+export type GetExchangeDetailedInfoOp = {
+ op: WalletApiOperation.GetExchangeDetailedInfo;
+ request: AddExchangeRequest;
+ response: ExchangeDetailedResponse;
+};
+// GetExchangeDetailedInfo = "getExchangeDetailedInfo"
+
+```
+```typescript
+export interface ExchangeDetailedResponse {
+ exchange: ExchangeFullDetails;
+}
+
+```
+```typescript
+export interface ExchangeFullDetails {
+ exchangeBaseUrl: string;
+ currency: string;
+ paytoUris: string[];
+ auditors: ExchangeAuditor[];
+ wireInfo: WireInfo;
+ denomFees: DenomOperationMap<FeeDescription[]>;
+ transferFees: Record<string, FeeDescription[]>;
+ globalFees: FeeDescription[];
+}
+
+```
+```typescript
+export interface WireInfo {
+ feesForType: WireFeeMap;
+ accounts: ExchangeWireAccount[];
+}
+
+```
+```typescript
+export interface ExchangeWireAccount {
+ payto_uri: string;
+ conversion_url?: string;
+ credit_restrictions: AccountRestriction[];
+ debit_restrictions: AccountRestriction[];
+ master_sig: EddsaSignatureString;
+ bank_label?: string;
+ priority?: number;
+}
+
+```
+```typescript
+export interface FeeDescription {
+ group: string;
+ from: AbsoluteTime;
+ until: AbsoluteTime;
+ fee?: AmountString;
+}
+
+```
+
+### GetExchangeEntryByUrlOp
+```typescript
+/**
+ * Get the current terms of a service of an exchange.
+ */
+export type GetExchangeEntryByUrlOp = {
+ op: WalletApiOperation.GetExchangeEntryByUrl;
+ request: GetExchangeEntryByUrlRequest;
+ response: GetExchangeEntryByUrlResponse;
+};
+// GetExchangeEntryByUrl = "getExchangeEntryByUrl"
+
+```
+```typescript
+export interface GetExchangeEntryByUrlRequest {
+ exchangeBaseUrl: string;
+}
+
+```
+
+### GetExchangeResourcesOp
+```typescript
+/**
+ * Get resources associated with an exchange.
+ */
+export type GetExchangeResourcesOp = {
+ op: WalletApiOperation.GetExchangeResources;
+ request: GetExchangeResourcesRequest;
+ response: GetExchangeResourcesResponse;
+};
+// GetExchangeResources = "getExchangeResources"
+
+```
+```typescript
+export interface GetExchangeResourcesRequest {
+ exchangeBaseUrl: string;
+}
+
+```
+```typescript
+export interface GetExchangeResourcesResponse {
+ hasResources: boolean;
+}
+
+```
+
+### DeleteExchangeOp
+```typescript
+/**
+ * Get resources associated with an exchange.
+ */
+export type DeleteExchangeOp = {
+ op: WalletApiOperation.GetExchangeResources;
+ request: DeleteExchangeRequest;
+ response: EmptyObject;
+};
+// GetExchangeResources = "getExchangeResources"
+
+```
+```typescript
+export interface DeleteExchangeRequest {
+ exchangeBaseUrl: string;
+ purge?: boolean;
+}
+
+```
+
+### GetCurrencySpecificationOp
+```typescript
+export type GetCurrencySpecificationOp = {
+ op: WalletApiOperation.GetCurrencySpecification;
+ request: GetCurrencySpecificationRequest;
+ response: GetCurrencySpecificationResponse;
+};
+// GetCurrencySpecification = "getCurrencySpecification"
+
+```
+```typescript
+export interface GetCurrencySpecificationRequest {
+ scope: ScopeInfo;
+}
+
+```
+```typescript
+export interface GetCurrencySpecificationResponse {
+ currencySpecification: CurrencySpecification;
+}
+
+```
+
+### GenerateDepositGroupTxIdOp
+```typescript
+/**
+ * Generate a fresh transaction ID for a deposit group.
+ *
+ * The resulting transaction ID can be specified when creating
+ * a deposit group, so that the client can already start waiting for notifications
+ * on that specific deposit group before the GreateDepositGroup request returns.
+ */
+export type GenerateDepositGroupTxIdOp = {
+ op: WalletApiOperation.GenerateDepositGroupTxId;
+ request: EmptyObject;
+ response: TxIdResponse;
+};
+// GenerateDepositGroupTxId = "generateDepositGroupTxId"
+
+```
+```typescript
+export interface TxIdResponse {
+ transactionId: TransactionIdStr;
+}
+
+```
+
+### CreateDepositGroupOp
+```typescript
+/**
+ * Create a new deposit group.
+ *
+ * Deposit groups are used to deposit multiple coins to a bank
+ * account, usually the wallet user's own bank account.
+ */
+export type CreateDepositGroupOp = {
+ op: WalletApiOperation.CreateDepositGroup;
+ request: CreateDepositGroupRequest;
+ response: CreateDepositGroupResponse;
+};
+// CreateDepositGroup = "createDepositGroup"
+
+```
+```typescript
+export interface CreateDepositGroupRequest {
+ /**
+ * Pre-allocated transaction ID.
+ * Allows clients to easily handle notifications
+ * that occur while the operation has been created but
+ * before the creation request has returned.
+ */
+ transactionId?: TransactionIdStr;
+ depositPaytoUri: string;
+ amount: AmountString;
+}
+
+```
+```typescript
+export interface CreateDepositGroupResponse {
+ depositGroupId: string;
+ transactionId: TransactionIdStr;
+}
+
+```
+
+### PrepareDepositOp
+```typescript
+export type PrepareDepositOp = {
+ op: WalletApiOperation.PrepareDeposit;
+ request: PrepareDepositRequest;
+ response: PrepareDepositResponse;
+};
+// PrepareDeposit = "prepareDeposit"
+
+```
+```typescript
+export interface PrepareDepositRequest {
+ depositPaytoUri: string;
+ amount: AmountString;
+}
+
+```
+```typescript
+export interface PrepareDepositResponse {
+ totalDepositCost: AmountString;
+ effectiveDepositAmount: AmountString;
+ fees: DepositGroupFees;
+}
+
+```
+```typescript
+export interface DepositGroupFees {
+ coin: AmountString;
+ wire: AmountString;
+ refresh: AmountString;
+}
+
+```
+
+### ExportBackupRecoveryOp
+```typescript
+/**
+ * Export the recovery information for the wallet.
+ */
+export type ExportBackupRecoveryOp = {
+ op: WalletApiOperation.ExportBackupRecovery;
+ request: EmptyObject;
+ response: BackupRecovery;
+};
+// ExportBackupRecovery = "exportBackupRecovery"
+
+```
+
+### ImportBackupRecoveryOp
+```typescript
+/**
+ * Import recovery information into the wallet.
+ */
+export type ImportBackupRecoveryOp = {
+ op: WalletApiOperation.ImportBackupRecovery;
+ request: RecoveryLoadRequest;
+ response: EmptyObject;
+};
+// ImportBackupRecovery = "importBackupRecovery"
+
+```
+```typescript
+/**
+ * Load recovery information into the wallet.
+ */
+export interface RecoveryLoadRequest {
+ recovery: BackupRecovery;
+ strategy?: RecoveryMergeStrategy;
+}
+
+```
+```typescript
+/**
+ * Strategy for loading recovery information.
+ */
+export declare enum RecoveryMergeStrategy {
+ /**
+ * Keep the local wallet root key, import and take over providers.
+ */
+ Ours = "ours",
+ /**
+ * Migrate to the wallet root key from the recovery information.
+ */
+ Theirs = "theirs",
+}
+
+```
+
+### RunBackupCycleOp
+```typescript
+/**
+ * Manually make and upload a backup.
+ */
+export type RunBackupCycleOp = {
+ op: WalletApiOperation.RunBackupCycle;
+ request: RunBackupCycleRequest;
+ response: EmptyObject;
+};
+// RunBackupCycle = "runBackupCycle"
+
+```
+```typescript
+export interface RunBackupCycleRequest {
+ /**
+ * List of providers to backup or empty for all known providers.
+ */
+ providers?: Array<string>;
+}
+
+```
+
+### ExportBackupOp
+```typescript
+export type ExportBackupOp = {
+ op: WalletApiOperation.ExportBackup;
+ request: EmptyObject;
+ response: EmptyObject;
+};
+// ExportBackup = "exportBackup"
+
+```
+
+### AddBackupProviderOp
+```typescript
+/**
+ * Add a new backup provider.
+ */
+export type AddBackupProviderOp = {
+ op: WalletApiOperation.AddBackupProvider;
+ request: AddBackupProviderRequest;
+ response: AddBackupProviderResponse;
+};
+// AddBackupProvider = "addBackupProvider"
+
+```
+```typescript
+export interface AddBackupProviderRequest {
+ backupProviderBaseUrl: string;
+ name: string;
+ /**
+ * Activate the provider. Should only be done after
+ * the user has reviewed the provider.
+ */
+ activate?: boolean;
+}
+
+```
+```typescript
+export type AddBackupProviderResponse =
+ | AddBackupProviderOk
+ | AddBackupProviderPaymentRequired;
+
+```
+```typescript
+interface AddBackupProviderOk {
+ status: "ok";
+}
+
+```
+```typescript
+interface AddBackupProviderPaymentRequired {
+ status: "payment-required";
+ talerUri?: string;
+}
+
+```
+
+### RemoveBackupProviderOp
+```typescript
+export type RemoveBackupProviderOp = {
+ op: WalletApiOperation.RemoveBackupProvider;
+ request: RemoveBackupProviderRequest;
+ response: EmptyObject;
+};
+// RemoveBackupProvider = "removeBackupProvider"
+
+```
+```typescript
+export interface RemoveBackupProviderRequest {
+ provider: string;
+}
+
+```
+
+### GetBackupInfoOp
+```typescript
+/**
+ * Get some useful stats about the backup state.
+ */
+export type GetBackupInfoOp = {
+ op: WalletApiOperation.GetBackupInfo;
+ request: EmptyObject;
+ response: BackupInfo;
+};
+// GetBackupInfo = "getBackupInfo"
+
+```
+```typescript
+export interface BackupInfo {
+ walletRootPub: string;
+ deviceId: string;
+ providers: ProviderInfo[];
+}
+
+```
+```typescript
+/**
+ * Information about one provider.
+ *
+ * We don't store the account key here,
+ * as that's derived from the wallet root key.
+ */
+export interface ProviderInfo {
+ active: boolean;
+ syncProviderBaseUrl: string;
+ name: string;
+ terms?: BackupProviderTerms;
+ /**
+ * Last communication issue with the provider.
+ */
+ lastError?: TalerErrorDetail;
+ lastSuccessfulBackupTimestamp?: TalerPreciseTimestamp;
+ lastAttemptedBackupTimestamp?: TalerPreciseTimestamp;
+ paymentProposalIds: string[];
+ backupProblem?: BackupProblem;
+ paymentStatus: ProviderPaymentStatus;
+}
+
+```
+```typescript
+export interface BackupProviderTerms {
+ supportedProtocolVersion: string;
+ annualFee: AmountString;
+ storageLimitInMegabytes: number;
+}
+
+```
+```typescript
+export type BackupProblem =
+ | BackupUnreadableProblem
+ | BackupConflictingDeviceProblem;
+
+```
+```typescript
+export interface BackupUnreadableProblem {
+ type: "backup-unreadable";
+}
+
+```
+```typescript
+export interface BackupConflictingDeviceProblem {
+ type: "backup-conflicting-device";
+ otherDeviceId: string;
+ myDeviceId: string;
+ backupTimestamp: AbsoluteTime;
+}
+
+```
+```typescript
+export type ProviderPaymentStatus =
+ | ProviderPaymentTermsChanged
+ | ProviderPaymentPaid
+ | ProviderPaymentInsufficientBalance
+ | ProviderPaymentUnpaid
+ | ProviderPaymentPending;
+
+```
+```typescript
+export interface ProviderPaymentTermsChanged {
+ type: ProviderPaymentType.TermsChanged;
+ paidUntil: AbsoluteTime;
+ oldTerms: BackupProviderTerms;
+ newTerms: BackupProviderTerms;
+}
+
+```
+```typescript
+export interface ProviderPaymentPaid {
+ type: ProviderPaymentType.Paid;
+ paidUntil: AbsoluteTime;
+}
+
+```
+```typescript
+export interface ProviderPaymentInsufficientBalance {
+ type: ProviderPaymentType.InsufficientBalance;
+ amount: AmountString;
+}
+
+```
+```typescript
+export interface ProviderPaymentUnpaid {
+ type: ProviderPaymentType.Unpaid;
+}
+
+```
+```typescript
+export interface ProviderPaymentPending {
+ type: ProviderPaymentType.Pending;
+ talerUri?: string;
+}
+
+```
+
+### SetWalletDeviceIdOp
+```typescript
+/**
+ * Set the internal device ID of the wallet, used to
+ * identify whether a different/new wallet is accessing
+ * the backup of another wallet.
+ */
+export type SetWalletDeviceIdOp = {
+ op: WalletApiOperation.SetWalletDeviceId;
+ request: SetWalletDeviceIdRequest;
+ response: EmptyObject;
+};
+// SetWalletDeviceId = "setWalletDeviceId"
+
+```
+```typescript
+export interface SetWalletDeviceIdRequest {
+ /**
+ * New wallet device ID to set.
+ */
+ walletDeviceId: string;
+}
+
+```
+
+### ListStoredBackupsOp
+```typescript
+export type ListStoredBackupsOp = {
+ op: WalletApiOperation.ListStoredBackups;
+ request: EmptyObject;
+ response: StoredBackupList;
+};
+// ListStoredBackups = "listStoredBackups"
+
+```
+```typescript
+export interface StoredBackupList {
+ storedBackups: {
+ name: string;
+ }[];
+}
+
+```
+
+### CreateStoredBackupsOp
+```typescript
+export type CreateStoredBackupsOp = {
+ op: WalletApiOperation.CreateStoredBackup;
+ request: EmptyObject;
+ response: CreateStoredBackupResponse;
+};
+// CreateStoredBackup = "createStoredBackup"
+
+```
+```typescript
+export interface CreateStoredBackupResponse {
+ name: string;
+}
+
+```
+
+### RecoverStoredBackupsOp
+```typescript
+export type RecoverStoredBackupsOp = {
+ op: WalletApiOperation.RecoverStoredBackup;
+ request: RecoverStoredBackupRequest;
+ response: EmptyObject;
+};
+// RecoverStoredBackup = "recoverStoredBackup"
+
+```
+```typescript
+export interface RecoverStoredBackupRequest {
+ name: string;
+}
+
+```
+
+### DeleteStoredBackupOp
+```typescript
+export type DeleteStoredBackupOp = {
+ op: WalletApiOperation.DeleteStoredBackup;
+ request: DeleteStoredBackupRequest;
+ response: EmptyObject;
+};
+// DeleteStoredBackup = "deleteStoredBackup"
+
+```
+```typescript
+export interface DeleteStoredBackupRequest {
+ name: string;
+}
+
+```
+
+### CheckPeerPushDebitOp
+```typescript
+/**
+ * Check if initiating a peer push payment is possible
+ * based on the funds in the wallet.
+ */
+export type CheckPeerPushDebitOp = {
+ op: WalletApiOperation.CheckPeerPushDebit;
+ request: CheckPeerPushDebitRequest;
+ response: CheckPeerPushDebitResponse;
+};
+// CheckPeerPushDebit = "checkPeerPushDebit"
+
+```
+```typescript
+export interface CheckPeerPushDebitRequest {
+ /**
+ * Preferred exchange to use for the p2p payment.
+ */
+ exchangeBaseUrl?: string;
+ /**
+ * Instructed amount.
+ *
+ * FIXME: Allow specifying the instructed amount type.
+ */
+ amount: AmountString;
+}
+
+```
+```typescript
+export interface CheckPeerPushDebitResponse {
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+ exchangeBaseUrl: string;
+ /**
+ * Maximum expiration date, based on how close the coins
+ * used for the payment are to expiry.
+ *
+ * The value is based on when the wallet would typically
+ * automatically refresh the coins on its own, leaving enough
+ * time to get a refund for the push payment and refresh the
+ * coin.
+ */
+ maxExpirationDate: TalerProtocolTimestamp;
+}
+
+```
+
+### InitiatePeerPushDebitOp
+```typescript
+/**
+ * Initiate an outgoing peer push payment.
+ */
+export type InitiatePeerPushDebitOp = {
+ op: WalletApiOperation.InitiatePeerPushDebit;
+ request: InitiatePeerPushDebitRequest;
+ response: InitiatePeerPushDebitResponse;
+};
+// InitiatePeerPushDebit = "initiatePeerPushDebit"
+
+```
+```typescript
+export interface InitiatePeerPushDebitRequest {
+ exchangeBaseUrl?: string;
+ partialContractTerms: PeerContractTerms;
+}
+
+```
+```typescript
+export interface InitiatePeerPushDebitResponse {
+ exchangeBaseUrl: string;
+ pursePub: string;
+ mergePriv: string;
+ contractPriv: string;
+ transactionId: TransactionIdStr;
+}
+
+```
+
+### PreparePeerPushCreditOp
+```typescript
+/**
+ * Check an incoming peer push payment.
+ */
+export type PreparePeerPushCreditOp = {
+ op: WalletApiOperation.PreparePeerPushCredit;
+ request: PreparePeerPushCreditRequest;
+ response: PreparePeerPushCreditResponse;
+};
+// PreparePeerPushCredit = "preparePeerPushCredit"
+
+```
+```typescript
+export interface PreparePeerPushCreditRequest {
+ talerUri: string;
+}
+
+```
+```typescript
+export interface PreparePeerPushCreditResponse {
+ contractTerms: PeerContractTerms;
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+ transactionId: TransactionIdStr;
+ exchangeBaseUrl: string;
+ /**
+ * @deprecated use transaction ID instead.
+ */
+ peerPushCreditId: string;
+ /**
+ * @deprecated
+ */
+ amount: AmountString;
+}
+
+```
+
+### ConfirmPeerPushCreditOp
+```typescript
+/**
+ * Accept an incoming peer push payment.
+ */
+export type ConfirmPeerPushCreditOp = {
+ op: WalletApiOperation.ConfirmPeerPushCredit;
+ request: ConfirmPeerPushCreditRequest;
+ response: EmptyObject;
+};
+// ConfirmPeerPushCredit = "confirmPeerPushCredit"
+
+```
+```typescript
+export interface ConfirmPeerPushCreditRequest {
+ transactionId: string;
+}
+
+```
+
+### CheckPeerPullCreditOp
+```typescript
+/**
+ * Check fees for an outgoing peer pull payment.
+ */
+export type CheckPeerPullCreditOp = {
+ op: WalletApiOperation.CheckPeerPullCredit;
+ request: CheckPeerPullCreditRequest;
+ response: CheckPeerPullCreditResponse;
+};
+// CheckPeerPullCredit = "checkPeerPullCredit"
+
+```
+```typescript
+export interface CheckPeerPullCreditRequest {
+ exchangeBaseUrl?: string;
+ amount: AmountString;
+}
+
+```
+```typescript
+export interface CheckPeerPullCreditResponse {
+ exchangeBaseUrl: string;
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+ /**
+ * Number of coins that will be used,
+ * can be used by the UI to warn if excessively large.
+ */
+ numCoins: number;
+}
+
+```
+
+### InitiatePeerPullCreditOp
+```typescript
+/**
+ * Initiate an outgoing peer pull payment.
+ */
+export type InitiatePeerPullCreditOp = {
+ op: WalletApiOperation.InitiatePeerPullCredit;
+ request: InitiatePeerPullCreditRequest;
+ response: InitiatePeerPullCreditResponse;
+};
+// InitiatePeerPullCredit = "initiatePeerPullCredit"
+
+```
+```typescript
+export interface InitiatePeerPullCreditRequest {
+ exchangeBaseUrl?: string;
+ partialContractTerms: PeerContractTerms;
+}
+
+```
+```typescript
+export interface InitiatePeerPullCreditResponse {
+ /**
+ * Taler URI for the other party to make the payment
+ * that was requested.
+ *
+ * @deprecated since it's not necessarily valid yet until the tx is in the right state
+ */
+ talerUri: string;
+ transactionId: TransactionIdStr;
+}
+
+```
+
+### PreparePeerPullDebitOp
+```typescript
+/**
+ * Prepare for an incoming peer pull payment.
+ */
+export type PreparePeerPullDebitOp = {
+ op: WalletApiOperation.PreparePeerPullDebit;
+ request: PreparePeerPullDebitRequest;
+ response: PreparePeerPullDebitResponse;
+};
+// PreparePeerPullDebit = "preparePeerPullDebit"
+
+```
+```typescript
+export interface PreparePeerPullDebitRequest {
+ talerUri: string;
+}
+
+```
+```typescript
+export interface PreparePeerPullDebitResponse {
+ contractTerms: PeerContractTerms;
+ /**
+ * @deprecated Redundant field with bad name, will be removed soon.
+ */
+ amount: AmountString;
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+ peerPullDebitId: string;
+ transactionId: TransactionIdStr;
+}
+
+```
+
+### ConfirmPeerPullDebitOp
+```typescript
+/**
+ * Accept an incoming peer pull payment (i.e. pay the other party).
+ */
+export type ConfirmPeerPullDebitOp = {
+ op: WalletApiOperation.ConfirmPeerPullDebit;
+ request: ConfirmPeerPullDebitRequest;
+ response: EmptyObject;
+};
+// ConfirmPeerPullDebit = "confirmPeerPullDebit"
+
+```
+```typescript
+export interface ConfirmPeerPullDebitRequest {
+ transactionId: TransactionIdStr;
+}
+
+```
+
+### ValidateIbanOp
+```typescript
+export type ValidateIbanOp = {
+ op: WalletApiOperation.ValidateIban;
+ request: ValidateIbanRequest;
+ response: ValidateIbanResponse;
+};
+// ValidateIban = "validateIban"
+
+```
+```typescript
+export interface ValidateIbanRequest {
+ iban: string;
+}
+
+```
+```typescript
+export interface ValidateIbanResponse {
+ valid: boolean;
+}
+
+```
+
+### ExportDbOp
+```typescript
+/**
+ * Export the wallet database's contents to JSON.
+ */
+export type ExportDbOp = {
+ op: WalletApiOperation.ExportDb;
+ request: EmptyObject;
+ response: any;
+};
+// ExportDb = "exportDb"
+
+```
+
+### ImportDbOp
+```typescript
+export type ImportDbOp = {
+ op: WalletApiOperation.ImportDb;
+ request: ImportDbRequest;
+ response: EmptyObject;
+};
+// ImportDb = "importDb"
+
+```
+```typescript
+export interface ImportDbRequest {
+ dump: any;
+}
+
+```
+
+### ClearDbOp
+```typescript
+/**
+ * Dangerously clear the whole wallet database.
+ */
+export type ClearDbOp = {
+ op: WalletApiOperation.ClearDb;
+ request: EmptyObject;
+ response: EmptyObject;
+};
+// ClearDb = "clearDb"
+
+```
+
+### RecycleOp
+```typescript
+/**
+ * Export a backup, clear the database and re-import it.
+ */
+export type RecycleOp = {
+ op: WalletApiOperation.Recycle;
+ request: EmptyObject;
+ response: EmptyObject;
+};
+// Recycle = "recycle"
+
+```
+
+### ApplyDevExperimentOp
+```typescript
+/**
+ * Apply a developer experiment to the current wallet state.
+ *
+ * This allows UI developers / testers to play around without
+ * an elaborate test environment.
+ */
+export type ApplyDevExperimentOp = {
+ op: WalletApiOperation.ApplyDevExperiment;
+ request: ApplyDevExperimentRequest;
+ response: EmptyObject;
+};
+// ApplyDevExperiment = "applyDevExperiment"
+
+```
+```typescript
+export interface ApplyDevExperimentRequest {
+ devExperimentUri: string;
+}
+
+```
+
+### RunIntegrationTestOp
+```typescript
+/**
+ * Run a simple integration test on a test deployment
+ * of the exchange and merchant.
+ */
+export type RunIntegrationTestOp = {
+ op: WalletApiOperation.RunIntegrationTest;
+ request: IntegrationTestArgs;
+ response: EmptyObject;
+};
+// RunIntegrationTest = "runIntegrationTest"
+
+```
+
+### RunIntegrationTestV2Op
+```typescript
+/**
+ * Run a simple integration test on a test deployment
+ * of the exchange and merchant.
+ */
+export type RunIntegrationTestV2Op = {
+ op: WalletApiOperation.RunIntegrationTestV2;
+ request: IntegrationTestArgs;
+ response: EmptyObject;
+};
+// RunIntegrationTestV2 = "runIntegrationTestV2"
+
+```
+
+### TestCryptoOp
+```typescript
+/**
+ * Test crypto worker.
+ */
+export type TestCryptoOp = {
+ op: WalletApiOperation.TestCrypto;
+ request: EmptyObject;
+ response: any;
+};
+// TestCrypto = "testCrypto"
+
+```
+
+### WithdrawTestBalanceOp
+```typescript
+/**
+ * Make withdrawal on a test deployment of the exchange
+ * and merchant.
+ */
+export type WithdrawTestBalanceOp = {
+ op: WalletApiOperation.WithdrawTestBalance;
+ request: WithdrawTestBalanceRequest;
+ response: EmptyObject;
+};
+// WithdrawTestBalance = "withdrawTestBalance"
+
+```
+```typescript
+export interface WithdrawTestBalanceRequest {
+ amount: AmountString;
+ /**
+ * Corebank API base URL.
+ */
+ corebankApiBaseUrl: string;
+ exchangeBaseUrl: string;
+ forcedDenomSel?: ForcedDenomSel;
+}
+
+```
+
+### WithdrawTestkudosOp
+```typescript
+/**
+ * Make a withdrawal of testkudos on test.taler.net.
+ */
+export type WithdrawTestkudosOp = {
+ op: WalletApiOperation.WithdrawTestkudos;
+ request: EmptyObject;
+ response: EmptyObject;
+};
+// WithdrawTestkudos = "withdrawTestkudos"
+
+```
+
+### TestPayOp
+```typescript
+/**
+ * Make a test payment using a test deployment of
+ * the exchange and merchant.
+ */
+export type TestPayOp = {
+ op: WalletApiOperation.TestPay;
+ request: TestPayArgs;
+ response: TestPayResult;
+};
+// TestPay = "testPay"
+
+```
+```typescript
+export interface TestPayArgs {
+ merchantBaseUrl: string;
+ merchantAuthToken?: string;
+ amount: AmountString;
+ summary: string;
+ forcedCoinSel?: ForcedCoinSel;
+}
+
+```
+```typescript
+export interface TestPayResult {
+ /**
+ * Number of coins used for the payment.
+ */
+ numCoins: number;
+}
+
+```
+
+### GetPendingTasksOp
+```typescript
+/**
+ * Get wallet-internal pending tasks.
+ *
+ * @deprecated
+ */
+export type GetPendingTasksOp = {
+ op: WalletApiOperation.GetPendingOperations;
+ request: EmptyObject;
+ response: any;
+};
+// GetPendingOperations = "getPendingOperations"
+
+```
+
+### GetActiveTasksOp
+```typescript
+export type GetActiveTasksOp = {
+ op: WalletApiOperation.GetActiveTasks;
+ request: EmptyObject;
+ response: GetActiveTasks;
+};
+// GetActiveTasks = "getActiveTasks"
+
+```
+
+### DumpCoinsOp
+```typescript
+/**
+ * Dump all coins of the wallet in a simple JSON format.
+ */
+export type DumpCoinsOp = {
+ op: WalletApiOperation.DumpCoins;
+ request: EmptyObject;
+ response: CoinDumpJson;
+};
+// DumpCoins = "dumpCoins"
+
+```
+```typescript
+/**
+ * Easy to process format for the public data of coins
+ * managed by the wallet.
+ */
+export interface CoinDumpJson {
+ coins: Array<{
+ /**
+ * The coin's denomination's public key.
+ */
+ denom_pub: DenominationPubKey;
+ /**
+ * Hash of denom_pub.
+ */
+ denom_pub_hash: string;
+ /**
+ * Value of the denomination (without any fees).
+ */
+ denom_value: string;
+ /**
+ * Public key of the coin.
+ */
+ coin_pub: string;
+ /**
+ * Base URL of the exchange for the coin.
+ */
+ exchange_base_url: string;
+ /**
+ * Public key of the parent coin.
+ * Only present if this coin was obtained via refreshing.
+ */
+ refresh_parent_coin_pub: string | undefined;
+ /**
+ * Public key of the reserve for this coin.
+ * Only present if this coin was obtained via refreshing.
+ */
+ withdrawal_reserve_pub: string | undefined;
+ coin_status: CoinStatus;
+ spend_allocation:
+ | {
+ id: string;
+ amount: AmountString;
+ }
+ | undefined;
+ /**
+ * Information about the age restriction
+ */
+ ageCommitmentProof: AgeCommitmentProof | undefined;
+ }>;
+}
+
+```
+```typescript
+export type DenominationPubKey = RsaDenominationPubKey | CsDenominationPubKey;
+
+```
+```typescript
+export interface RsaDenominationPubKey {
+ readonly cipher: DenomKeyType.Rsa;
+ readonly rsa_public_key: string;
+ readonly age_mask: number;
+}
+
+```
+```typescript
+export interface CsDenominationPubKey {
+ readonly cipher: DenomKeyType.ClauseSchnorr;
+ readonly age_mask: number;
+ readonly cs_public_key: string;
+}
+
+```
+```typescript
+/**
+ * Status of a coin.
+ */
+export declare enum CoinStatus {
+ /**
+ * Withdrawn and never shown to anybody.
+ */
+ Fresh = "fresh",
+ /**
+ * Coin was lost as the denomination is not usable anymore.
+ */
+ DenomLoss = "denom-loss",
+ /**
+ * Fresh, but currently marked as "suspended", thus won't be used
+ * for spending. Used for testing.
+ */
+ FreshSuspended = "fresh-suspended",
+ /**
+ * A coin that has been spent and refreshed.
+ */
+ Dormant = "dormant",
+}
+
+```
+```typescript
+export interface AgeCommitmentProof {
+ commitment: AgeCommitment;
+ proof: AgeProof;
+}
+
+```
+```typescript
+export interface AgeCommitment {
+ mask: number;
+ /**
+ * Public keys, one for each age group specified in the age mask.
+ */
+ publicKeys: Edx25519PublicKeyEnc[];
+}
+
+```
+```typescript
+export type Edx25519PublicKeyEnc = FlavorP<string, "Edx25519PublicKeyEnc", 32>;
+
+```
+```typescript
+export type FlavorP<T, FlavorT extends string, S extends number> = T & {
+ _flavor?: `taler.${FlavorT}`;
+ _size?: S;
+};
+
+```
+```typescript
+export interface AgeProof {
+ /**
+ * Private keys. Typically smaller than the number of public keys,
+ * because we drop private keys from age groups that are restricted.
+ */
+ privateKeys: Edx25519PrivateKeyEnc[];
+}
+
+```
+```typescript
+export type Edx25519PrivateKeyEnc = FlavorP<
+ string,
+ "Edx25519PrivateKeyEnc",
+ 64
+>;
+
+```
+
+### TestingSetTimetravelOp
+```typescript
+/**
+ * Add an offset to the wallet's internal time.
+ */
+export type TestingSetTimetravelOp = {
+ op: WalletApiOperation.TestingSetTimetravel;
+ request: TestingSetTimetravelRequest;
+ response: EmptyObject;
+};
+// TestingSetTimetravel = "testingSetTimetravel"
+
+```
+```typescript
+export interface TestingSetTimetravelRequest {
+ offsetMs: number;
+}
+
+```
+
+### TestingListTasksForTransactionOp
+```typescript
+/**
+ * Add an offset to the wallet's internal time.
+ */
+export type TestingListTasksForTransactionOp = {
+ op: WalletApiOperation.TestingListTaskForTransaction;
+ request: TestingListTasksForTransactionRequest;
+ response: TestingListTasksForTransactionsResponse;
+};
+// TestingListTaskForTransaction = "testingListTasksForTransaction"
+
+```
+```typescript
+export interface TestingListTasksForTransactionRequest {
+ transactionId: TransactionIdStr;
+}
+
+```
+```typescript
+export interface TestingListTasksForTransactionsResponse {
+ taskIdList: string[];
+}
+
+```
+
+### TestingWaitTransactionsFinalOp
+```typescript
+/**
+ * Wait until all transactions are in a final state.
+ */
+export type TestingWaitTransactionsFinalOp = {
+ op: WalletApiOperation.TestingWaitTransactionsFinal;
+ request: EmptyObject;
+ response: EmptyObject;
+};
+// TestingWaitTransactionsFinal = "testingWaitTransactionsFinal"
+
+```
+
+### TestingWaitRefreshesFinalOp
+```typescript
+/**
+ * Wait until all refresh transactions are in a final state.
+ */
+export type TestingWaitRefreshesFinalOp = {
+ op: WalletApiOperation.TestingWaitRefreshesFinal;
+ request: EmptyObject;
+ response: EmptyObject;
+};
+// TestingWaitRefreshesFinal = "testingWaitRefreshesFinal"
+
+```
+
+### TestingWaitTransactionStateOp
+```typescript
+/**
+ * Wait until a transaction is in a particular state.
+ */
+export type TestingWaitTransactionStateOp = {
+ op: WalletApiOperation.TestingWaitTransactionState;
+ request: TestingWaitTransactionRequest;
+ response: EmptyObject;
+};
+// TestingWaitTransactionState = "testingWaitTransactionState"
+
+```
+```typescript
+export interface TestingWaitTransactionRequest {
+ transactionId: TransactionIdStr;
+ txState: TransactionState;
+}
+
+```
+
+### TestingPingOp
+```typescript
+export type TestingPingOp = {
+ op: WalletApiOperation.TestingPing;
+ request: EmptyObject;
+ response: EmptyObject;
+};
+// TestingPing = "testingPing"
+
+```
+
+### TestingGetDenomStatsOp
+```typescript
+/**
+ * Get stats about an exchange denomination.
+ */
+export type TestingGetDenomStatsOp = {
+ op: WalletApiOperation.TestingGetDenomStats;
+ request: TestingGetDenomStatsRequest;
+ response: TestingGetDenomStatsResponse;
+};
+// TestingGetDenomStats = "testingGetDenomStats"
+
+```
+```typescript
+export interface TestingGetDenomStatsRequest {
+ exchangeBaseUrl: string;
+}
+
+```
+```typescript
+export interface TestingGetDenomStatsResponse {
+ numKnown: number;
+ numOffered: number;
+ numLost: number;
+}
+
+```
+
+### SetCoinSuspendedOp
+```typescript
+/**
+ * Set a coin as (un-)suspended.
+ * Suspended coins won't be used for payments.
+ */
+export type SetCoinSuspendedOp = {
+ op: WalletApiOperation.SetCoinSuspended;
+ request: SetCoinSuspendedRequest;
+ response: EmptyObject;
+};
+// SetCoinSuspended = "setCoinSuspended"
+
+```
+```typescript
+export interface SetCoinSuspendedRequest {
+ coinPub: string;
+ suspended: boolean;
+}
+
+```
+
+### ForceRefreshOp
+```typescript
+/**
+ * Force a refresh on coins where it would not
+ * be necessary.
+ */
+export type ForceRefreshOp = {
+ op: WalletApiOperation.ForceRefresh;
+ request: ForceRefreshRequest;
+ response: EmptyObject;
+};
+// ForceRefresh = "forceRefresh"
+
+```
+```typescript
+export interface ForceRefreshRequest {
+ refreshCoinSpecs: RefreshCoinSpec[];
+}
+
+```
+```typescript
+export interface RefreshCoinSpec {
+ coinPub: string;
+ amount?: AmountString;
+}
+
+```
+
+## Common Declarations
+```typescript
+export interface InitRequest {
+ config?: PartialWalletRunConfig;
+}
+```
+```typescript
+export interface PartialWalletRunConfig {
+ builtin?: Partial<WalletRunConfig["builtin"]>;
+ testing?: Partial<WalletRunConfig["testing"]>;
+ features?: Partial<WalletRunConfig["features"]>;
+}
+```
+```typescript
+export interface WalletRunConfig {
+ /**
+ * Initialization values useful for a complete startup.
+ *
+ * These are values may be overridden by different wallets
+ */
+ builtin: {
+ exchanges: BuiltinExchange[];
+ };
+ /**
+ * Unsafe options which it should only be used to create
+ * testing environment.
+ */
+ testing: {
+ /**
+ * Allow withdrawal of denominations even though they are about to expire.
+ */
+ denomselAllowLate: boolean;
+ devModeActive: boolean;
+ insecureTrustExchange: boolean;
+ preventThrottling: boolean;
+ skipDefaults: boolean;
+ emitObservabilityEvents?: boolean;
+ };
+ /**
+ * Configurations values that may be safe to show to the user
+ */
+ features: {
+ allowHttp: boolean;
+ };
+}
+```
+```typescript
+export interface BuiltinExchange {
+ exchangeBaseUrl: string;
+ currencyHint: string;
+}
+```
+```typescript
+export interface InitResponse {
+ versionInfo: WalletCoreVersion;
+}
+```
+```typescript
+export interface WalletCoreVersion {
+ implementationSemver: string;
+ implementationGitHash: string;
+ /**
+ * Wallet-core protocol version supported by this implementation
+ * of the API ("server" version).
+ */
+ version: string;
+ exchange: string;
+ merchant: string;
+ bankIntegrationApiRange: string;
+ bankConversionApiRange: string;
+ corebankApiRange: string;
+ /**
+ * @deprecated as bank was split into multiple APIs with separate versioning
+ */
+ bank: string;
+ /**
+ * @deprecated
+ */
+ hash: string | undefined;
+ /**
+ * @deprecated will be removed
+ */
+ devMode: boolean;
+}
+```
+```typescript
+export type ScopeInfo = ScopeInfoGlobal | ScopeInfoExchange | ScopeInfoAuditor;
+```
+```typescript
+export type AmountString = string & {
+ [__amount_str]: true;
+};
+```
+```typescript
+/**
+ * How the amount should be interpreted in a transaction
+ * Effective = how the balance is change
+ * Raw = effective amount without fee
+ *
+ * Depending on the transaction, raw can be higher than effective
+ */
+export declare enum TransactionAmountMode {
+ Effective = "effective",
+ Raw = "raw",
+}
+```
+```typescript
+export interface ConvertAmountRequest {
+ amount: AmountString;
+ type: TransactionAmountMode;
+}
+```
+```typescript
+export interface AmountResponse {
+ effectiveAmount: AmountString;
+ rawAmount: AmountString;
+}
+```
+```typescript
+export interface GetAmountRequest {
+ currency: string;
+}
+```
+```typescript
+export interface TransactionsResponse {
+ transactions: Transaction[];
+}
+```
+```typescript
+export type Transaction =
+ | TransactionWithdrawal
+ | TransactionPayment
+ | TransactionRefund
+ | TransactionReward
+ | TransactionRefresh
+ | TransactionDeposit
+ | TransactionPeerPullCredit
+ | TransactionPeerPullDebit
+ | TransactionPeerPushCredit
+ | TransactionPeerPushDebit
+ | TransactionInternalWithdrawal
+ | TransactionRecoup
+ | TransactionDenomLoss;
+```
+```typescript
+/**
+ * A withdrawal transaction (either bank-integrated or manual).
+ */
+export interface TransactionWithdrawal extends TransactionCommon {
+ type: TransactionType.Withdrawal;
+ /**
+ * Exchange of the withdrawal.
+ */
+ exchangeBaseUrl: string;
+ /**
+ * Amount that got subtracted from the reserve balance.
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount that actually was (or will be) added to the wallet's balance.
+ */
+ amountEffective: AmountString;
+ withdrawalDetails: WithdrawalDetails;
+}
+```
+```typescript
+export interface TransactionCommon {
+ transactionId: TransactionIdStr;
+ type: TransactionType;
+ timestamp: TalerPreciseTimestamp;
+ /**
+ * Transaction state, as per DD37.
+ */
+ txState: TransactionState;
+ /**
+ * Possible transitions based on the current state.
+ */
+ txActions: TransactionAction[];
+ /**
+ * Raw amount of the transaction (exclusive of fees or other extra costs).
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount added or removed from the wallet's balance (including all fees and other costs).
+ */
+ amountEffective: AmountString;
+ error?: TalerErrorDetail;
+ /**
+ * If the transaction minor state is in KycRequired this field is going to
+ * have the location where the user need to go to complete KYC information.
+ */
+ kycUrl?: string;
+}
+```
+```typescript
+export type TransactionIdStr = `txn:${string}:${string}` & {
+ [__txId]: true;
+};
+```
+```typescript
+export declare enum TransactionType {
+ Withdrawal = "withdrawal",
+ InternalWithdrawal = "internal-withdrawal",
+ Payment = "payment",
+ Refund = "refund",
+ Refresh = "refresh",
+ Reward = "reward",
+ Deposit = "deposit",
+ PeerPushDebit = "peer-push-debit",
+ PeerPushCredit = "peer-push-credit",
+ PeerPullDebit = "peer-pull-debit",
+ PeerPullCredit = "peer-pull-credit",
+ Recoup = "recoup",
+ DenomLoss = "denom-loss",
+}
+```
+```typescript
+/**
+ * Precise timestamp, typically used in the wallet-core
+ * API but not in other Taler APIs so far.
+ */
+export interface TalerPreciseTimestamp {
+ /**
+ * Seconds (as integer) since epoch.
+ */
+ readonly t_s: number | "never";
+ /**
+ * Optional microsecond offset (non-negative integer).
+ */
+ readonly off_us?: number;
+ readonly _flavor?: typeof flavor_TalerPreciseTimestamp;
+}
+```
+```typescript
+export interface TalerProtocolTimestamp {
+ /**
+ * Seconds (as integer) since epoch.
+ */
+ readonly t_s: number | "never";
+ readonly _flavor?: typeof flavor_TalerProtocolTimestamp;
+}
+```
+```typescript
+export interface TransactionState {
+ major: TransactionMajorState;
+ minor?: TransactionMinorState;
+}
+```
+```typescript
+export declare enum TransactionMajorState {
+ None = "none",
+ Pending = "pending",
+ Done = "done",
+ Aborting = "aborting",
+ Aborted = "aborted",
+ Suspended = "suspended",
+ Dialog = "dialog",
+ SuspendedAborting = "suspended-aborting",
+ Failed = "failed",
+ Expired = "expired",
+ Deleted = "deleted",
+}
+```
+```typescript
+export declare enum TransactionMinorState {
+ Unknown = "unknown",
+ Deposit = "deposit",
+ KycRequired = "kyc",
+ AmlRequired = "aml",
+ MergeKycRequired = "merge-kyc",
+ Track = "track",
+ SubmitPayment = "submit-payment",
+ RebindSession = "rebind-session",
+ Refresh = "refresh",
+ Pickup = "pickup",
+ AutoRefund = "auto-refund",
+ User = "user",
+ Bank = "bank",
+ Exchange = "exchange",
+ ClaimProposal = "claim-proposal",
+ CheckRefund = "check-refund",
+ CreatePurse = "create-purse",
+ DeletePurse = "delete-purse",
+ RefreshExpired = "refresh-expired",
+ Ready = "ready",
+ Merge = "merge",
+ Repurchase = "repurchase",
+ BankRegisterReserve = "bank-register-reserve",
+ BankConfirmTransfer = "bank-confirm-transfer",
+ WithdrawCoins = "withdraw-coins",
+ ExchangeWaitReserve = "exchange-wait-reserve",
+ AbortingBank = "aborting-bank",
+ Aborting = "aborting",
+ Refused = "refused",
+ Withdraw = "withdraw",
+ MerchantOrderProposed = "merchant-order-proposed",
+ Proposed = "proposed",
+ RefundAvailable = "refund-available",
+ AcceptRefund = "accept-refund",
+ PaidByOther = "paid-by-other",
+}
+```
+```typescript
+export declare enum TransactionAction {
+ Delete = "delete",
+ Suspend = "suspend",
+ Resume = "resume",
+ Abort = "abort",
+ Fail = "fail",
+ Retry = "retry",
+}
+```
+```typescript
+export interface TalerErrorDetail {
+ code: TalerErrorCode;
+ when?: AbsoluteTime;
+ hint?: string;
+ [x: string]: unknown;
+}
+```
+```typescript
+export interface AbsoluteTime {
+ /**
+ * Timestamp in milliseconds.
+ */
+ readonly t_ms: number | "never";
+ readonly _flavor?: typeof flavor_AbsoluteTime;
+ [opaque_AbsoluteTime]: true;
+}
+```
+```typescript
+export interface Duration {
+ /**
+ * Duration in milliseconds.
+ */
+ readonly d_ms: number | "forever";
+}
+```
+```typescript
+export interface TalerProtocolDuration {
+ readonly d_us: number | "forever";
+}
+```
+```typescript
+export type WithdrawalDetails =
+ | WithdrawalDetailsForManualTransfer
+ | WithdrawalDetailsForTalerBankIntegrationApi;
+```
+```typescript
+interface WithdrawalDetailsForManualTransfer {
+ type: WithdrawalType.ManualTransfer;
+ /**
+ * Payto URIs that the exchange supports.
+ *
+ * Already contains the amount and message.
+ *
+ * @deprecated in favor of exchangeCreditAccounts
+ */
+ exchangePaytoUris: string[];
+ exchangeCreditAccountDetails?: WithdrawalExchangeAccountDetails[];
+ reservePub: string;
+ /**
+ * Is the reserve ready for withdrawal?
+ */
+ reserveIsReady: boolean;
+}
+```
+```typescript
+export interface WithdrawalExchangeAccountDetails {
+ /**
+ * Payto URI to credit the exchange.
+ *
+ * Depending on whether the (manual!) withdrawal is accepted or just
+ * being checked, this already includes the subject with the
+ * reserve public key.
+ */
+ paytoUri: string;
+ /**
+ * Status that indicates whether the account can be used
+ * by the user to send funds for a withdrawal.
+ *
+ * ok: account should be shown to the user
+ * error: account should not be shown to the user, UIs might render the error (in conversionError),
+ * especially in dev mode.
+ */
+ status: "ok" | "error";
+ /**
+ * Transfer amount. Might be in a different currency than the requested
+ * amount for withdrawal.
+ *
+ * Absent if this is a conversion account and the conversion failed.
+ */
+ transferAmount?: AmountString;
+ /**
+ * Currency specification for the external currency.
+ *
+ * Only included if this account requires a currency conversion.
+ */
+ currencySpecification?: CurrencySpecification;
+ /**
+ * Further restrictions for sending money to the
+ * exchange.
+ */
+ creditRestrictions?: AccountRestriction[];
+ /**
+ * Label given to the account or the account's bank by the exchange.
+ */
+ bankLabel?: string;
+ priority?: number;
+ /**
+ * Error that happened when attempting to request the conversion rate.
+ */
+ conversionError?: TalerErrorDetail;
+}
+```
+```typescript
+export interface CurrencySpecification {
+ name: string;
+ num_fractional_input_digits: Integer;
+ num_fractional_normal_digits: Integer;
+ num_fractional_trailing_zero_digits: Integer;
+ alt_unit_names: {
+ [log10: string]: string;
+ };
+}
+```
+```typescript
+export type AccountRestriction =
+ | RegexAccountRestriction
+ | DenyAllAccountRestriction;
+```
+```typescript
+export interface RegexAccountRestriction {
+ type: "regex";
+ payto_regex: string;
+ human_hint: string;
+ human_hint_i18n?: InternationalizedString;
+}
+```
+```typescript
+export interface InternationalizedString {
+ [lang_tag: string]: string;
+}
+```
+```typescript
+export interface DenyAllAccountRestriction {
+ type: "deny";
+}
+```
+```typescript
+interface WithdrawalDetailsForTalerBankIntegrationApi {
+ type: WithdrawalType.TalerBankIntegrationApi;
+ /**
+ * Set to true if the bank has confirmed the withdrawal, false if not.
+ * An unconfirmed withdrawal usually requires user-input and should be highlighted in the UI.
+ * See also bankConfirmationUrl below.
+ */
+ confirmed: boolean;
+ /**
+ * If the withdrawal is unconfirmed, this can include a URL for user
+ * initiated confirmation.
+ */
+ bankConfirmationUrl?: string;
+ reservePub: string;
+ /**
+ * Is the reserve ready for withdrawal?
+ */
+ reserveIsReady: boolean;
+ exchangeCreditAccountDetails?: WithdrawalExchangeAccountDetails[];
+}
+```
+```typescript
+export interface TransactionPayment extends TransactionCommon {
+ type: TransactionType.Payment;
+ /**
+ * Additional information about the payment.
+ */
+ info: OrderShortInfo;
+ /**
+ * Wallet-internal end-to-end identifier for the payment.
+ */
+ proposalId: string;
+ /**
+ * Amount that must be paid for the contract
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount that was paid, including deposit, wire and refresh fees.
+ */
+ amountEffective: AmountString;
+ /**
+ * Amount that has been refunded by the merchant
+ */
+ totalRefundRaw: AmountString;
+ /**
+ * Amount will be added to the wallet's balance after fees and refreshing
+ */
+ totalRefundEffective: AmountString;
+ /**
+ * Amount pending to be picked up
+ */
+ refundPending: AmountString | undefined;
+ /**
+ * Reference to applied refunds
+ */
+ refunds: RefundInfoShort[];
+ /**
+ * Is the wallet currently checking for a refund?
+ */
+ refundQueryActive: boolean;
+ /**
+ * Does this purchase has an pos validation
+ */
+ posConfirmation: string | undefined;
+}
+```
+```typescript
+export interface OrderShortInfo {
+ /**
+ * Order ID, uniquely identifies the order within a merchant instance
+ */
+ orderId: string;
+ /**
+ * Hash of the contract terms.
+ */
+ contractTermsHash: string;
+ /**
+ * More information about the merchant
+ */
+ merchant: MerchantInfo;
+ /**
+ * Summary of the order, given by the merchant
+ */
+ summary: string;
+ /**
+ * Map from IETF BCP 47 language tags to localized summaries
+ */
+ summary_i18n?: InternationalizedString;
+ /**
+ * URL of the fulfillment, given by the merchant
+ */
+ fulfillmentUrl?: string;
+ /**
+ * Plain text message that should be shown to the user
+ * when the payment is complete.
+ */
+ fulfillmentMessage?: string;
+ /**
+ * Translations of fulfillmentMessage.
+ */
+ fulfillmentMessage_i18n?: InternationalizedString;
+}
+```
+```typescript
+export interface MerchantInfo {
+ name: string;
+ email?: string;
+ website?: string;
+ logo?: ImageDataUrl;
+ address?: Location;
+ jurisdiction?: Location;
+}
+```
+```typescript
+export interface Location {
+ country?: string;
+ country_subdivision?: string;
+ district?: string;
+ town?: string;
+ town_location?: string;
+ post_code?: string;
+ street?: string;
+ building_name?: string;
+ building_number?: string;
+ address_lines?: string[];
+}
+```
+```typescript
+export interface RefundInfoShort {
+ transactionId: string;
+ timestamp: TalerProtocolTimestamp;
+ amountEffective: AmountString;
+ amountRaw: AmountString;
+}
+```
+```typescript
+export interface TransactionRefund extends TransactionCommon {
+ type: TransactionType.Refund;
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+ refundedTransactionId: string;
+ paymentInfo: RefundPaymentInfo | undefined;
+}
+```
+```typescript
+/**
+ * Summary information about the payment that we got a refund for.
+ */
+export interface RefundPaymentInfo {
+ summary: string;
+ summary_i18n?: InternationalizedString;
+ /**
+ * More information about the merchant
+ */
+ merchant: MerchantInfo;
+}
+```
+```typescript
+export interface TransactionReward extends TransactionCommon {
+ type: TransactionType.Reward;
+ amountRaw: AmountString;
+ /**
+ * More information about the merchant
+ */
+ amountEffective: AmountString;
+ merchantBaseUrl: string;
+}
+```
+```typescript
+/**
+ * A transaction shown for refreshes.
+ * Only shown for (1) refreshes not associated with other transactions
+ * and (2) refreshes in an error state.
+ */
+export interface TransactionRefresh extends TransactionCommon {
+ type: TransactionType.Refresh;
+ refreshReason: RefreshReason;
+ /**
+ * Transaction ID that caused this refresh.
+ */
+ originatingTransactionId?: string;
+ /**
+ * Always zero for refreshes
+ */
+ amountRaw: AmountString;
+ /**
+ * Fees, i.e. the effective, negative effect of the refresh
+ * on the balance.
+ *
+ * Only applicable for stand-alone refreshes, and zero for
+ * other refreshes where the transaction itself accounts for the
+ * refresh fee.
+ */
+ amountEffective: AmountString;
+ refreshInputAmount: AmountString;
+ refreshOutputAmount: AmountString;
+}
+```
+```typescript
+/**
+ * Reasons for why a coin is being refreshed.
+ */
+export declare enum RefreshReason {
+ Manual = "manual",
+ PayMerchant = "pay-merchant",
+ PayDeposit = "pay-deposit",
+ PayPeerPush = "pay-peer-push",
+ PayPeerPull = "pay-peer-pull",
+ Refund = "refund",
+ AbortPay = "abort-pay",
+ AbortDeposit = "abort-deposit",
+ AbortPeerPushDebit = "abort-peer-push-debit",
+ AbortPeerPullDebit = "abort-peer-pull-debit",
+ Recoup = "recoup",
+ BackupRestored = "backup-restored",
+ Scheduled = "scheduled",
+}
+```
+```typescript
+/**
+ * Deposit transaction, which effectively sends
+ * money from this wallet somewhere else.
+ */
+export interface TransactionDeposit extends TransactionCommon {
+ type: TransactionType.Deposit;
+ depositGroupId: string;
+ /**
+ * Target for the deposit.
+ */
+ targetPaytoUri: string;
+ /**
+ * Raw amount that is being deposited
+ */
+ amountRaw: AmountString;
+ /**
+ * Effective amount that is being deposited
+ */
+ amountEffective: AmountString;
+ wireTransferDeadline: TalerProtocolTimestamp;
+ wireTransferProgress: number;
+ /**
+ * Did all the deposit requests succeed?
+ */
+ deposited: boolean;
+ trackingState: Array<DepositTransactionTrackingState>;
+}
+```
+```typescript
+export interface DepositTransactionTrackingState {
+ wireTransferId: string;
+ timestampExecuted: TalerProtocolTimestamp;
+ amountRaw: AmountString;
+ wireFee: AmountString;
+}
+```
+```typescript
+/**
+ * Credit because we were paid for a P2P invoice we created.
+ */
+export interface TransactionPeerPullCredit extends TransactionCommon {
+ type: TransactionType.PeerPullCredit;
+ info: PeerInfoShort;
+ /**
+ * Exchange used.
+ */
+ exchangeBaseUrl: string;
+ /**
+ * Amount that got subtracted from the reserve balance.
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount that actually was (or will be) added to the wallet's balance.
+ */
+ amountEffective: AmountString;
+ /**
+ * URI to send to the other party.
+ *
+ * Only available in the right state.
+ */
+ talerUri: string | undefined;
+}
+```
+```typescript
+export interface PeerInfoShort {
+ expiration: TalerProtocolTimestamp | undefined;
+ summary: string | undefined;
+}
+```
+```typescript
+/**
+ * Debit because we paid someone's invoice.
+ */
+export interface TransactionPeerPullDebit extends TransactionCommon {
+ type: TransactionType.PeerPullDebit;
+ info: PeerInfoShort;
+ /**
+ * Exchange used.
+ */
+ exchangeBaseUrl: string;
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+}
+```
+```typescript
+/**
+ * We received money via a P2P payment.
+ */
+export interface TransactionPeerPushCredit extends TransactionCommon {
+ type: TransactionType.PeerPushCredit;
+ info: PeerInfoShort;
+ /**
+ * Exchange used.
+ */
+ exchangeBaseUrl: string;
+ /**
+ * Amount that got subtracted from the reserve balance.
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount that actually was (or will be) added to the wallet's balance.
+ */
+ amountEffective: AmountString;
+}
+```
+```typescript
+/**
+ * We sent money via a P2P payment.
+ */
+export interface TransactionPeerPushDebit extends TransactionCommon {
+ type: TransactionType.PeerPushDebit;
+ info: PeerInfoShort;
+ /**
+ * Exchange used.
+ */
+ exchangeBaseUrl: string;
+ /**
+ * Amount that got subtracted from the reserve balance.
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount that actually was (or will be) added to the wallet's balance.
+ */
+ amountEffective: AmountString;
+ /**
+ * URI to accept the payment.
+ *
+ * Only present if the transaction is in a state where the other party can
+ * accept the payment.
+ */
+ talerUri?: string;
+}
+```
+```typescript
+/**
+ * Internal withdrawal operation, only reported on request.
+ *
+ * Some transactions (peer-*-credit) internally do a withdrawal,
+ * but only the peer-*-credit transaction is reported.
+ *
+ * The internal withdrawal transaction allows to access the details of
+ * the underlying withdrawal for testing/debugging.
+ *
+ * It is usually not reported, so that amounts of transactions properly
+ * add up, since the amountEffecive of the withdrawal is already reported
+ * in the peer-*-credit transaction.
+ */
+export interface TransactionInternalWithdrawal extends TransactionCommon {
+ type: TransactionType.InternalWithdrawal;
+ /**
+ * Exchange of the withdrawal.
+ */
+ exchangeBaseUrl: string;
+ /**
+ * Amount that got subtracted from the reserve balance.
+ */
+ amountRaw: AmountString;
+ /**
+ * Amount that actually was (or will be) added to the wallet's balance.
+ */
+ amountEffective: AmountString;
+ withdrawalDetails: WithdrawalDetails;
+}
+```
+```typescript
+/**
+ * The exchange revoked a key and the wallet recoups funds.
+ */
+export interface TransactionRecoup extends TransactionCommon {
+ type: TransactionType.Recoup;
+}
+```
+```typescript
+/**
+ * A transaction to indicate financial loss due to denominations
+ * that became unusable for deposits.
+ */
+export interface TransactionDenomLoss extends TransactionCommon {
+ type: TransactionType.DenomLoss;
+ lossEventType: DenomLossEventType;
+ exchangeBaseUrl: string;
+}
+```
+```typescript
+export declare enum DenomLossEventType {
+ DenomExpired = "denom-expired",
+ DenomVanished = "denom-vanished",
+ DenomUnoffered = "denom-unoffered",
+}
+```
+```typescript
+export interface AbortTransactionRequest {
+ transactionId: TransactionIdStr;
+}
+```
+```typescript
+/**
+ * Info about an exchange entry in the wallet.
+ */
+export interface ExchangeListItem {
+ exchangeBaseUrl: string;
+ masterPub: string | undefined;
+ currency: string;
+ paytoUris: string[];
+ tosStatus: ExchangeTosStatus;
+ exchangeEntryStatus: ExchangeEntryStatus;
+ exchangeUpdateStatus: ExchangeUpdateStatus;
+ ageRestrictionOptions: number[];
+ /**
+ * P2P payments are disabled with this exchange
+ * (e.g. because no global fees are configured).
+ */
+ peerPaymentsDisabled: boolean;
+ /**
+ * Set to true if this exchange doesn't charge any fees.
+ */
+ noFees: boolean;
+ scopeInfo: ScopeInfo;
+ lastUpdateTimestamp: TalerPreciseTimestamp | undefined;
+ /**
+ * Information about the last error that occurred when trying
+ * to update the exchange info.
+ */
+ lastUpdateErrorInfo?: OperationErrorInfo;
+}
+```
+```typescript
+export declare enum ExchangeTosStatus {
+ Pending = "pending",
+ Proposed = "proposed",
+ Accepted = "accepted",
+}
+```
+```typescript
+export declare enum ExchangeEntryStatus {
+ Preset = "preset",
+ Ephemeral = "ephemeral",
+ Used = "used",
+}
+```
+```typescript
+export declare enum ExchangeUpdateStatus {
+ Initial = "initial",
+ InitialUpdate = "initial-update",
+ Suspended = "suspended",
+ UnavailableUpdate = "unavailable-update",
+ Ready = "ready",
+ ReadyUpdate = "ready-update",
+}
+```
+```typescript
+export interface OperationErrorInfo {
+ error: TalerErrorDetail;
+}
+```
+```typescript
+export interface ForcedDenomSel {
+ denoms: {
+ value: AmountString;
+ count: number;
+ }[];
+}
+```
+```typescript
+/**
+ * Result of a prepare pay operation.
+ */
+export type PreparePayResult =
+ | PreparePayResultInsufficientBalance
+ | PreparePayResultAlreadyConfirmed
+ | PreparePayResultPaymentPossible;
+```
+```typescript
+export interface PreparePayResultInsufficientBalance {
+ status: PreparePayResultType.InsufficientBalance;
+ transactionId: TransactionIdStr;
+ /**
+ * @deprecated use transactionId
+ */
+ proposalId: string;
+ contractTerms: MerchantContractTerms;
+ amountRaw: AmountString;
+ talerUri: string;
+ balanceDetails: PaymentInsufficientBalanceDetails;
+}
+```
+```typescript
+/**
+ * Contract terms from a merchant.
+ * FIXME: Add type field!
+ */
+export interface MerchantContractTerms {
+ h_wire: string;
+ auto_refund?: TalerProtocolDuration;
+ wire_method: string;
+ summary: string;
+ summary_i18n?: InternationalizedString;
+ order_id: string;
+ amount: string;
+ nonce: string;
+ pay_deadline: TalerProtocolTimestamp;
+ merchant: MerchantInfo;
+ merchant_pub: string;
+ delivery_date?: TalerProtocolTimestamp;
+ delivery_location?: Location;
+ exchanges: ExchangeHandle[];
+ products?: Product[];
+ refund_deadline: TalerProtocolTimestamp;
+ wire_transfer_deadline: TalerProtocolTimestamp;
+ timestamp: TalerProtocolTimestamp;
+ merchant_base_url: string;
+ fulfillment_url?: string;
+ public_reorder_url?: string;
+ fulfillment_message?: string;
+ fulfillment_message_i18n?: InternationalizedString;
+ max_fee: string;
+ extra?: any;
+ minimum_age?: Integer;
+}
+```
+```typescript
+/**
+ * Information about an exchange as stored inside a
+ * merchant's contract terms.
+ */
+export interface ExchangeHandle {
+ url: string;
+ master_pub: EddsaPublicKeyString;
+}
+```
+```typescript
+export interface Product {
+ product_id?: string;
+ description: string;
+ description_i18n?: InternationalizedString;
+ quantity?: Integer;
+ unit?: string;
+ price?: AmountString;
+ image?: ImageDataUrl;
+ taxes?: Tax[];
+ delivery_date?: TalerProtocolTimestamp;
+}
+```
+```typescript
+export interface Tax {
+ name: string;
+ tax: AmountString;
+}
+```
+```typescript
+/**
+ * Detailed reason for why the wallet's balance is insufficient.
+ */
+export interface PaymentInsufficientBalanceDetails {
+ /**
+ * Amount requested by the merchant.
+ */
+ amountRequested: AmountString;
+ /**
+ * Balance of type "available" (see balance.ts for definition).
+ */
+ balanceAvailable: AmountString;
+ /**
+ * Balance of type "material" (see balance.ts for definition).
+ */
+ balanceMaterial: AmountString;
+ /**
+ * Balance of type "age-acceptable" (see balance.ts for definition).
+ */
+ balanceAgeAcceptable: AmountString;
+ /**
+ * Balance of type "merchant-acceptable" (see balance.ts for definition).
+ */
+ balanceReceiverAcceptable: AmountString;
+ /**
+ * Balance of type "merchant-depositable" (see balance.ts for definition).
+ */
+ balanceReceiverDepositable: AmountString;
+ balanceExchangeDepositable: AmountString;
+ /**
+ * Maximum effective amount that the wallet can spend,
+ * when all fees are paid by the wallet.
+ */
+ maxEffectiveSpendAmount: AmountString;
+ perExchange: {
+ [url: string]: {
+ balanceAvailable: AmountString;
+ balanceMaterial: AmountString;
+ balanceExchangeDepositable: AmountString;
+ balanceAgeAcceptable: AmountString;
+ balanceReceiverAcceptable: AmountString;
+ balanceReceiverDepositable: AmountString;
+ maxEffectiveSpendAmount: AmountString;
+ /**
+ * Exchange doesn't have global fees configured for the relevant year,
+ * p2p payments aren't possible.
+ */
+ missingGlobalFees: boolean;
+ };
+ };
+}
+```
+```typescript
+export interface PreparePayResultAlreadyConfirmed {
+ status: PreparePayResultType.AlreadyConfirmed;
+ transactionId: TransactionIdStr;
+ contractTerms: MerchantContractTerms;
+ paid: boolean;
+ amountRaw: AmountString;
+ amountEffective: AmountString | undefined;
+ contractTermsHash: string;
+ /**
+ * @deprecated use transactionId
+ */
+ proposalId: string;
+ talerUri: string;
+}
+```
+```typescript
+/**
+ * Payment is possible.
+ */
+export interface PreparePayResultPaymentPossible {
+ status: PreparePayResultType.PaymentPossible;
+ transactionId: TransactionIdStr;
+ /**
+ * @deprecated use transactionId instead
+ */
+ proposalId: string;
+ contractTerms: MerchantContractTerms;
+ contractTermsHash: string;
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+ talerUri: string;
+}
+```
+```typescript
+/**
+ * Forced coin selection for deposits/payments.
+ */
+export interface ForcedCoinSel {
+ coins: {
+ value: AmountString;
+ contribution: AmountString;
+ }[];
+}
+```
+```typescript
+export interface AddExchangeRequest {
+ exchangeBaseUrl: string;
+ /**
+ * @deprecated use a separate API call to start a forced exchange update instead
+ */
+ forceUpdate?: boolean;
+ masterPub?: string;
+}
+```
+```typescript
+export interface AcceptExchangeTosRequest {
+ exchangeBaseUrl: string;
+}
+```
+```typescript
+export interface BackupRecovery {
+ walletRootPriv: string;
+ providers: {
+ name: string;
+ url: string;
+ }[];
+}
+```
+```typescript
+/**
+ * Contract terms between two wallets (as opposed to a merchant and wallet).
+ */
+export interface PeerContractTerms {
+ amount: AmountString;
+ summary: string;
+ purse_expiration: TalerProtocolTimestamp;
+}
+```
+```typescript
+export interface IntegrationTestArgs {
+ exchangeBaseUrl: string;
+ corebankApiBaseUrl: string;
+ merchantBaseUrl: string;
+ merchantAuthToken?: string;
+ amountToWithdraw: AmountString;
+ amountToSpend: AmountString;
+}
+```