gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-taler-mdb] branch master updated: add images for errors


From: gnunet
Subject: [taler-taler-mdb] branch master updated: add images for errors
Date: Sat, 13 Jan 2024 19:24:56 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository taler-mdb.

The following commit(s) were added to refs/heads/master by this push:
     new b31d2af  add images for errors
b31d2af is described below

commit b31d2af5910632ac5d845df24abfe278d50bdf6f
Author: Christian Grothoff <grothoff@gnunet.org>
AuthorDate: Sat Jan 13 19:24:52 2024 +0100

    add images for errors
---
 contrib/Makefile.am                            |  23 ++
 contrib/png/backend-auth-failure.png           | Bin 0 -> 214380 bytes
 contrib/png/backend-dns-resolution-failure.png | Bin 0 -> 39978 bytes
 contrib/png/backend-no-webserver.png           | Bin 0 -> 36708 bytes
 contrib/png/backend-unreachable.png            | Bin 0 -> 35611 bytes
 contrib/png/backend-x509-cert-bad.png          | Bin 0 -> 30694 bytes
 contrib/png/child-died.png                     | Bin 0 -> 29994 bytes
 contrib/png/err-num-read-fail.png              | Bin 0 -> 27458 bytes
 contrib/png/maintenance.png                    | Bin 0 -> 28329 bytes
 contrib/png/no-ip.png                          | Bin 0 -> 26469 bytes
 contrib/svg/backend-auth-failure.svg           |  71 ++++++
 contrib/svg/backend-dns-resolution-failure.svg |  71 ++++++
 contrib/svg/backend-no-webserver.svg           |  71 ++++++
 contrib/svg/backend-unreachable.svg            | 126 ++++++++++
 contrib/svg/backend-x509-cert-bad.svg          |  71 ++++++
 contrib/svg/child-died.svg                     |  71 ++++++
 contrib/svg/err-num-read-fail.svg              |  71 ++++++
 contrib/svg/maintenance.svg                    |  71 ++++++
 contrib/svg/no-ip.svg                          |  71 ++++++
 contrib/taler-mdb-show.sh                      |  41 ++++
 debian/taler-mdb.postrm.debhelper              |   2 +-
 debian/taler-mdb.service                       |   2 +-
 debian/taler-mdb.substvars                     |   2 +-
 src/Makefile.am                                |  10 +-
 src/taler-mdb-display.c                        | 312 +++++++++++++++++++++++++
 25 files changed, 1082 insertions(+), 4 deletions(-)

diff --git a/contrib/Makefile.am b/contrib/Makefile.am
index ade84a2..01065de 100644
--- a/contrib/Makefile.am
+++ b/contrib/Makefile.am
@@ -1,9 +1,32 @@
 SUBDIRS = .
 
+imgdir=$(datadir)/taler/mdb
+imgdir_DATA = \
+  png/backend-auth-failure.png \
+  png/backend-no-webserver.png \
+  png/backend-x509-cert-bad.png \
+  png/err-num-read-fail.png \
+  png/no-ip.png \
+  png/backend-dns-resolution-failure.png \
+  png/backend-unreachable.png \
+  png/child-died.png \
+  png/maintenance.png 
+
 bin_SCRIPTS = \
   taler-mdb-network-check.sh
 
 EXTRA_DIST = \
   $(bin_SCRIPTS) \
+  $(imgdir_DATA) \
+  svg/backend-auth-failure.svg \
+  svg/backend-no-webserver.svg \
+  svg/backend-x509-cert-bad.svg \
+  svg/err-num-read-fail.svg \
+  svg/no-ip.svg \
+  svg/backend-dns-resolution-failure.svg \
+  svg/backend-unreachable.svg \
+  svg/child-died.svg \
+  svg/maintenance.svg \
+  taler-machine.penpot \
   uncrustify.cfg \
   uncrustify_precommit
diff --git a/contrib/png/backend-auth-failure.png 
b/contrib/png/backend-auth-failure.png
new file mode 100644
index 0000000..bacb351
Binary files /dev/null and b/contrib/png/backend-auth-failure.png differ
diff --git a/contrib/png/backend-dns-resolution-failure.png 
b/contrib/png/backend-dns-resolution-failure.png
new file mode 100644
index 0000000..7cb510e
Binary files /dev/null and b/contrib/png/backend-dns-resolution-failure.png 
differ
diff --git a/contrib/png/backend-no-webserver.png 
b/contrib/png/backend-no-webserver.png
new file mode 100644
index 0000000..9d31220
Binary files /dev/null and b/contrib/png/backend-no-webserver.png differ
diff --git a/contrib/png/backend-unreachable.png 
b/contrib/png/backend-unreachable.png
new file mode 100644
index 0000000..8e3494c
Binary files /dev/null and b/contrib/png/backend-unreachable.png differ
diff --git a/contrib/png/backend-x509-cert-bad.png 
b/contrib/png/backend-x509-cert-bad.png
new file mode 100644
index 0000000..41fc0f4
Binary files /dev/null and b/contrib/png/backend-x509-cert-bad.png differ
diff --git a/contrib/png/child-died.png b/contrib/png/child-died.png
new file mode 100644
index 0000000..95ff3e3
Binary files /dev/null and b/contrib/png/child-died.png differ
diff --git a/contrib/png/err-num-read-fail.png 
b/contrib/png/err-num-read-fail.png
new file mode 100644
index 0000000..0cc11bb
Binary files /dev/null and b/contrib/png/err-num-read-fail.png differ
diff --git a/contrib/png/maintenance.png b/contrib/png/maintenance.png
new file mode 100644
index 0000000..b2005c7
Binary files /dev/null and b/contrib/png/maintenance.png differ
diff --git a/contrib/png/no-ip.png b/contrib/png/no-ip.png
new file mode 100644
index 0000000..cb09b4b
Binary files /dev/null and b/contrib/png/no-ip.png differ
diff --git a/contrib/svg/backend-auth-failure.svg 
b/contrib/svg/backend-auth-failure.svg
new file mode 100644
index 0000000..12140c7
--- /dev/null
+++ b/contrib/svg/backend-auth-failure.svg
@@ -0,0 +1,71 @@
+<svg xmlns:xlink="http://www.w3.org/1999/xlink"; width="480" 
xmlns="http://www.w3.org/2000/svg"; height="360" 
id="screenshot-2d5b5ebd-d89e-8002-8003-bc36eb0be5d7" viewBox="0 0 480 360" 
style="-webkit-print-color-adjust: exact;" fill="none" version="1.1"><style 
data-loading="false">@font-face {
+    font-family: 'sourcesanspro';
+    font-style: normal;
+    font-weight: 400;
+    font-display: block;
+    src: 
url(data:font/woff;base64,d09GRgABAAAAAHSMABQAAAABDCAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQVNFAAABvAAAAD4AAABQinOTf0ZGVE0AAAH8AAAAHAAAABxwkYDFR0RFRgAAAhgAAAAiAAAAJgAnARBHUE9TAAACPAAACzwAADXwmf/bv0dTVUIAAA14AAAA+gAAAa7khdupT1MvMgAADnQAAABXAAAAYGdamnRjbWFwAAAOzAAAAYkAAAHiSESmoGN2dCAAABBYAAAAVgAAAFYUww7lZnBnbQAAELAAAAGxAAACZVO0L6dnYXNwAAASZAAAAAgAAAAIAAAAEGdseWYAABJsAABQOgAAm1B0O5TbaGVhZAAAYqgAAAAxAAAANgkVq9doaGVhAABi3AAAAB8AAAAkDmAFi2htdHgAAGL8AAACOgAAA6h47lnNbG9jYQAAZTgAAAHIAAAB1smHp
 [...]
+  }
+/* cyrillic-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAADvwABIAAAAAjVwAADuKAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoFOG5JCHDYGYACCWAhUCYM8EQwKgegwgdA5C4NaABKBeAE2AiQDhzAEIAWCdAcgDIJJG1F+FdwYN3AeQFB+677abITtcRB8qCaK0k06uOD/rwlqyNg/1gG4OUtEGEGmirCEmqCnVGr8zsRmprTwyRyCfbliCOmQx9q6Mj5be/suy4CgRfxSwkp8rM+rmfWO0aAxlI/2bxhtsYiy9ZR3ZZiGPUfJ5eLCH0Og40B+5lS4+JZbREd3WtkRGvskl+f/s3v+f1b32tUPREaEUgQoBBjJsfAljRyMLk4N8XP7extjgFQJkkYTgjWLlAqleiNzwEBCpAY4YhuwTVIYgoyRGyKbgIgB0iHoB8XA+OZ8Ou2bGY00gAJL9liSUY6TeDNLnPx/QJA9Ln
 [...]
+  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, 
U+FE2E-FE2F;
+}
+/* cyrillic */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAACWcABIAAAAAWLAAACU5AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmobllYcNgZgAIIECFQJgzwRDAqBgWzzRAuCEAASgRQBNgIkA4QcBCAFgnQHIAyCSRtATxVsXGWGjQMMs+lnUBRVo81EUaPVpDXB/1+TmzJwD1T/qiCyZNisrEoqJdLUU4XdGFQhjzBlqe+erlaQaExxJzlQcKB465SpoPV52dI8GZeWGJIUaZVuemk76uNVowWj6Dl7XlNSpinpy1R//+CHMHBkVqDYZD5CSx/xEkR2/Fe927Mz/wxHZgogFOLL3jllJCU50T//nvXnJqmmwkDFJoWYDqR2oHRFf+0+Gd/y12qA5tatRDKsgSA2VhxVNl2DFql2TqkeY8jIjTIP+o4HxoNBSIVEjciRBq+PVWu2e4RzCU8YpmLECyEJFPCpR2O2y4d/ni
 [...]
+  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
+}
+/* greek-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAAXMABIAAAAACeAAAAVwAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANAhUCYM8EQwKg2iDSgsQABIUATYCJAMcBCAFgnQHIAyCSRt8CAieB2WbnmbLuYAwwpK8+iIe4P3r89wHDZaakNWCmB8R66SEWr+ILhpijnTqf6QAyyF8GVAOAPOWtmNg6llFXANTaQXCgXMubThOj6JRPCJsEWW3o1/4wX411uruvta/9FF8Zz50qenu3hVxmf4QIi1dRSzhkcR0SqA1QoiwzI2uAUbffgtBpA0YCssEQRChiaaAgMpAFvDsmKQshIEEer1l/u1J0Sbi8P6OJsQc3VHd6N0nlHe1MAhFbvPNcXJVWKNNekPqCYVx/lj8nqMi5BY4Pd6hectSY5E2Lll8SMf/HJXfEKEOfCtEMjEFBEHtpSkbjBK4aB1MIE
 [...]
+  unicode-range: U+1F00-1FFF;
+}
+/* greek */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABvIABIAAAAAOYgAABtmAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbjEocNgZgAIFkCFQJgzwRDArPdMcZC4FIABJwATYCJAODDAQgBYJ0ByAMgkkbLzMV3Bg3cB5AgtL+dFGUC8ojwf9fE9SQsQftHoablcBAJCnZiWWrVQuV5mlVJ2ZKaJa1O4xgpZOeStdtJqxoMWTv3rvjdJiEUBrhQCzjWKrrzr+v3IEvgtjCHD1r8RMqj2DUbHUyl4hbe5lIDkAEEv7BTsC+xxGuHLLDJzwiHqGlj3jhedKj/3NHyYLOPksVyBbSB1V0wvzv2n/ewGQCNDPJ4CNcyi6XXCtkT9WCK7lfZQjUdwVhSH0hX5Qr6naI5na/NTmQyDBHdEm3iAEoMEJG1gSjB2IwqiywRvWIHoLRPK+/h3l+b/sICQgQDouxxGMEJJh57K
 [...]
+  unicode-range: U+0370-03FF;
+}
+/* vietnamese */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABW4ABIAAAAANeQAABVYAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGjQbhlocNgZgAIEACFQJgzwRDArNRMZyC4IWABKBFAE2AiQDhCgEIAWCdAcgDIJJG0QwsxE2bBxAgN2rQPJ/ODCHzPnAWwWN2o42Fh2ljaWNtCCX3HjNpZ/jxeLZb4tm/kHiZ77mziCxZzy0cd8wTRJCiqDsSRqOR0gyC8+j3ffnZpLMGvMWRPfZ/87uBFagisZuqfzAb7P3+QVYiFknMxMjYpGImbB2t2HH1kadsmRrWXFGrkqX5TLxP6cqy2soa6trO4GdCmCmXToDmCtuKXj/ZyBcBEwQ3fvOvtv7qRSwgAQ4mq6lFACOaaw0uy1ldv9zuuKQSO46+Dl0Do9Oylz/M5dCGNyOU6+ueMEx1eTggIMuIVsO8utrIbVMv07ZhkxjhvHZUs
 [...]
+  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, 
U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, 
U+0329, U+1EA0-1EF9, U+20AB;
+}
+/* latin-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAC5gABIAAAAAcywAAC36AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGkAbjgwcgTAGYACDFAhUCYM8EQwKgbckgaVCC4N6ABKCCAE2AiQDh3AEIAWCdAcgDIJJGxxnJWybRvHgPADRiPpto6hJe1QiimDjIEDErxz8/+fkZAyBOmNq3n64RJGVYTsuMvUITcoKDzKbnypbeOMbTMui6C1taW9RKNHcVufFfHmORoTFgPXPgSnw9b5+VMOftv6L4lsP7Nfim5v2Fg/56vZtj9Xi2X1oL6wcCiUVkSRoowcKbqtiCxv72hEa+ySXh8iOvlc9XT27H+cQIKJzkEqRldoRFJE77dfP5dv9SY4YVAl4fHV0YXyVAjauylb1hue32fuUFViBOF1ahVEzCqsHioGKGBg5nZvTKYoJ6sSq6UQbF4o9l+mqzt3O2voMgP//fv
 [...]
+  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, 
U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAD2AABIAAAAAjnQAAD0aAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbmWQchV4GYACDIAhUCYM8EQwKgdx8gcR7C4QKABKCEAE2AiQDiBAEIAWCdAcgDIJJGzN/JezYiwK6AzihqSaqkQj7NFrlfHQg9jiQuO4X/P/nBM1EBrn5JK11TkWFUIRFnUFrFNvrPcp4DjlYevVgA0nxppzrUq2UwfojRitCYK27fdpSUHxF/dDCWlx/V1u8Guv6n+CPBeCi/9HtCEOUiBJRQoED6JkYbb+j7GNtuz+jRvSEZ/S00A7a2OhRipW6qzPAnRzRiJOHcO0f/0wy2b1bAsXMrrbsmBUhK0BVxx9efp7f5p/73qPEAETsPwy00f6KxdJqDIyKVRq5FmPZzFW5bKs2e9nKAG2zQ0Rdq2ivdNPVuxmRGFE4CwsLG8FAULHABE
 [...]
+  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, 
U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, 
U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+</style><g id="shape-2d5b5ebd-d89e-8002-8003-bc36eb0be5d7"><defs><clipPath 
class="frame-clip-def frame-clip" 
id="frame-clip-2d5b5ebd-d89e-8002-8003-bc36eb0be5d7-rumext-id-12"><rect rx="0" 
ry="0" x="0" y="0" width="480" height="360" transform="matrix(1.000000, 
0.000000, 0.000000, 1.000000, 0.000000, 0.000000)"/></clipPath></defs><g 
clip-path="url(#frame-clip-2d5b5ebd-d89e-8002-8003-bc36eb0be5d7-rumext-id-12)" 
fill="none"><clipPath class="frame-clip-def frame-clip" 
id="frame-clip-2d5b5ebd- [...]
\ No newline at end of file
diff --git a/contrib/svg/backend-dns-resolution-failure.svg 
b/contrib/svg/backend-dns-resolution-failure.svg
new file mode 100644
index 0000000..8f44ed4
--- /dev/null
+++ b/contrib/svg/backend-dns-resolution-failure.svg
@@ -0,0 +1,71 @@
+<svg xmlns:xlink="http://www.w3.org/1999/xlink"; width="480" 
xmlns="http://www.w3.org/2000/svg"; height="360" 
id="screenshot-2d5b5ebd-d89e-8002-8003-bc3b31c430c8" viewBox="0 0 480 360" 
style="-webkit-print-color-adjust: exact;" fill="none" version="1.1"><style 
data-loading="false">@font-face {
+    font-family: 'sourcesanspro';
+    font-style: normal;
+    font-weight: 400;
+    font-display: block;
+    src: 
url(data:font/woff;base64,d09GRgABAAAAAHSMABQAAAABDCAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQVNFAAABvAAAAD4AAABQinOTf0ZGVE0AAAH8AAAAHAAAABxwkYDFR0RFRgAAAhgAAAAiAAAAJgAnARBHUE9TAAACPAAACzwAADXwmf/bv0dTVUIAAA14AAAA+gAAAa7khdupT1MvMgAADnQAAABXAAAAYGdamnRjbWFwAAAOzAAAAYkAAAHiSESmoGN2dCAAABBYAAAAVgAAAFYUww7lZnBnbQAAELAAAAGxAAACZVO0L6dnYXNwAAASZAAAAAgAAAAIAAAAEGdseWYAABJsAABQOgAAm1B0O5TbaGVhZAAAYqgAAAAxAAAANgkVq9doaGVhAABi3AAAAB8AAAAkDmAFi2htdHgAAGL8AAACOgAAA6h47lnNbG9jYQAAZTgAAAHIAAAB1smHp
 [...]
+  }
+/* cyrillic-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAADvwABIAAAAAjVwAADuKAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoFOG5JCHDYGYACCWAhUCYM8EQwKgegwgdA5C4NaABKBeAE2AiQDhzAEIAWCdAcgDIJJG1F+FdwYN3AeQFB+677abITtcRB8qCaK0k06uOD/rwlqyNg/1gG4OUtEGEGmirCEmqCnVGr8zsRmprTwyRyCfbliCOmQx9q6Mj5be/suy4CgRfxSwkp8rM+rmfWO0aAxlI/2bxhtsYiy9ZR3ZZiGPUfJ5eLCH0Og40B+5lS4+JZbREd3WtkRGvskl+f/s3v+f1b32tUPREaEUgQoBBjJsfAljRyMLk4N8XP7extjgFQJkkYTgjWLlAqleiNzwEBCpAY4YhuwTVIYgoyRGyKbgIgB0iHoB8XA+OZ8Ou2bGY00gAJL9liSUY6TeDNLnPx/QJA9Ln
 [...]
+  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, 
U+FE2E-FE2F;
+}
+/* cyrillic */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAACWcABIAAAAAWLAAACU5AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmobllYcNgZgAIIECFQJgzwRDAqBgWzzRAuCEAASgRQBNgIkA4QcBCAFgnQHIAyCSRtATxVsXGWGjQMMs+lnUBRVo81EUaPVpDXB/1+TmzJwD1T/qiCyZNisrEoqJdLUU4XdGFQhjzBlqe+erlaQaExxJzlQcKB465SpoPV52dI8GZeWGJIUaZVuemk76uNVowWj6Dl7XlNSpinpy1R//+CHMHBkVqDYZD5CSx/xEkR2/Fe927Mz/wxHZgogFOLL3jllJCU50T//nvXnJqmmwkDFJoWYDqR2oHRFf+0+Gd/y12qA5tatRDKsgSA2VhxVNl2DFql2TqkeY8jIjTIP+o4HxoNBSIVEjciRBq+PVWu2e4RzCU8YpmLECyEJFPCpR2O2y4d/ni
 [...]
+  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
+}
+/* greek-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAAXMABIAAAAACeAAAAVwAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANAhUCYM8EQwKg2iDSgsQABIUATYCJAMcBCAFgnQHIAyCSRt8CAieB2WbnmbLuYAwwpK8+iIe4P3r89wHDZaakNWCmB8R66SEWr+ILhpijnTqf6QAyyF8GVAOAPOWtmNg6llFXANTaQXCgXMubThOj6JRPCJsEWW3o1/4wX411uruvta/9FF8Zz50qenu3hVxmf4QIi1dRSzhkcR0SqA1QoiwzI2uAUbffgtBpA0YCssEQRChiaaAgMpAFvDsmKQshIEEer1l/u1J0Sbi8P6OJsQc3VHd6N0nlHe1MAhFbvPNcXJVWKNNekPqCYVx/lj8nqMi5BY4Pd6hectSY5E2Lll8SMf/HJXfEKEOfCtEMjEFBEHtpSkbjBK4aB1MIE
 [...]
+  unicode-range: U+1F00-1FFF;
+}
+/* greek */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABvIABIAAAAAOYgAABtmAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbjEocNgZgAIFkCFQJgzwRDArPdMcZC4FIABJwATYCJAODDAQgBYJ0ByAMgkkbLzMV3Bg3cB5AgtL+dFGUC8ojwf9fE9SQsQftHoablcBAJCnZiWWrVQuV5mlVJ2ZKaJa1O4xgpZOeStdtJqxoMWTv3rvjdJiEUBrhQCzjWKrrzr+v3IEvgtjCHD1r8RMqj2DUbHUyl4hbe5lIDkAEEv7BTsC+xxGuHLLDJzwiHqGlj3jhedKj/3NHyYLOPksVyBbSB1V0wvzv2n/ewGQCNDPJ4CNcyi6XXCtkT9WCK7lfZQjUdwVhSH0hX5Qr6naI5na/NTmQyDBHdEm3iAEoMEJG1gSjB2IwqiywRvWIHoLRPK+/h3l+b/sICQgQDouxxGMEJJh57K
 [...]
+  unicode-range: U+0370-03FF;
+}
+/* vietnamese */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABW4ABIAAAAANeQAABVYAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGjQbhlocNgZgAIEACFQJgzwRDArNRMZyC4IWABKBFAE2AiQDhCgEIAWCdAcgDIJJG0QwsxE2bBxAgN2rQPJ/ODCHzPnAWwWN2o42Fh2ljaWNtCCX3HjNpZ/jxeLZb4tm/kHiZ77mziCxZzy0cd8wTRJCiqDsSRqOR0gyC8+j3ffnZpLMGvMWRPfZ/87uBFagisZuqfzAb7P3+QVYiFknMxMjYpGImbB2t2HH1kadsmRrWXFGrkqX5TLxP6cqy2soa6trO4GdCmCmXToDmCtuKXj/ZyBcBEwQ3fvOvtv7qRSwgAQ4mq6lFACOaaw0uy1ldv9zuuKQSO46+Dl0Do9Oylz/M5dCGNyOU6+ueMEx1eTggIMuIVsO8utrIbVMv07ZhkxjhvHZUs
 [...]
+  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, 
U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, 
U+0329, U+1EA0-1EF9, U+20AB;
+}
+/* latin-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAC5gABIAAAAAcywAAC36AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGkAbjgwcgTAGYACDFAhUCYM8EQwKgbckgaVCC4N6ABKCCAE2AiQDh3AEIAWCdAcgDIJJGxxnJWybRvHgPADRiPpto6hJe1QiimDjIEDErxz8/+fkZAyBOmNq3n64RJGVYTsuMvUITcoKDzKbnypbeOMbTMui6C1taW9RKNHcVufFfHmORoTFgPXPgSnw9b5+VMOftv6L4lsP7Nfim5v2Fg/56vZtj9Xi2X1oL6wcCiUVkSRoowcKbqtiCxv72hEa+ySXh8iOvlc9XT27H+cQIKJzkEqRldoRFJE77dfP5dv9SY4YVAl4fHV0YXyVAjauylb1hue32fuUFViBOF1ahVEzCqsHioGKGBg5nZvTKYoJ6sSq6UQbF4o9l+mqzt3O2voMgP//fv
 [...]
+  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, 
U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAD2AABIAAAAAjnQAAD0aAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbmWQchV4GYACDIAhUCYM8EQwKgdx8gcR7C4QKABKCEAE2AiQDiBAEIAWCdAcgDIJJGzN/JezYiwK6AzihqSaqkQj7NFrlfHQg9jiQuO4X/P/nBM1EBrn5JK11TkWFUIRFnUFrFNvrPcp4DjlYevVgA0nxppzrUq2UwfojRitCYK27fdpSUHxF/dDCWlx/V1u8Guv6n+CPBeCi/9HtCEOUiBJRQoED6JkYbb+j7GNtuz+jRvSEZ/S00A7a2OhRipW6qzPAnRzRiJOHcO0f/0wy2b1bAsXMrrbsmBUhK0BVxx9efp7f5p/73qPEAETsPwy00f6KxdJqDIyKVRq5FmPZzFW5bKs2e9nKAG2zQ0Rdq2ivdNPVuxmRGFE4CwsLG8FAULHABE
 [...]
+  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, 
U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, 
U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+</style><g id="shape-2d5b5ebd-d89e-8002-8003-bc3b31c430c8"><defs><clipPath 
class="frame-clip-def frame-clip" 
id="frame-clip-2d5b5ebd-d89e-8002-8003-bc3b31c430c8-rumext-id-1"><rect rx="0" 
ry="0" x="0" y="0" width="480" height="360" transform="matrix(1.000000, 
0.000000, 0.000000, 1.000000, 0.000000, 0.000000)"/></clipPath></defs><g 
clip-path="url(#frame-clip-2d5b5ebd-d89e-8002-8003-bc3b31c430c8-rumext-id-1)" 
fill="none"><clipPath class="frame-clip-def frame-clip" 
id="frame-clip-2d5b5ebd-d8 [...]
\ No newline at end of file
diff --git a/contrib/svg/backend-no-webserver.svg 
b/contrib/svg/backend-no-webserver.svg
new file mode 100644
index 0000000..0283a3e
--- /dev/null
+++ b/contrib/svg/backend-no-webserver.svg
@@ -0,0 +1,71 @@
+<svg xmlns:xlink="http://www.w3.org/1999/xlink"; width="480" 
xmlns="http://www.w3.org/2000/svg"; height="360" 
id="screenshot-2d5b5ebd-d89e-8002-8003-bc35b0c36344" viewBox="0 0 480 360" 
style="-webkit-print-color-adjust: exact;" fill="none" version="1.1"><style 
data-loading="false">@font-face {
+    font-family: 'sourcesanspro';
+    font-style: normal;
+    font-weight: 400;
+    font-display: block;
+    src: 
url(data:font/woff;base64,d09GRgABAAAAAHSMABQAAAABDCAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQVNFAAABvAAAAD4AAABQinOTf0ZGVE0AAAH8AAAAHAAAABxwkYDFR0RFRgAAAhgAAAAiAAAAJgAnARBHUE9TAAACPAAACzwAADXwmf/bv0dTVUIAAA14AAAA+gAAAa7khdupT1MvMgAADnQAAABXAAAAYGdamnRjbWFwAAAOzAAAAYkAAAHiSESmoGN2dCAAABBYAAAAVgAAAFYUww7lZnBnbQAAELAAAAGxAAACZVO0L6dnYXNwAAASZAAAAAgAAAAIAAAAEGdseWYAABJsAABQOgAAm1B0O5TbaGVhZAAAYqgAAAAxAAAANgkVq9doaGVhAABi3AAAAB8AAAAkDmAFi2htdHgAAGL8AAACOgAAA6h47lnNbG9jYQAAZTgAAAHIAAAB1smHp
 [...]
+  }
+/* cyrillic-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAADvwABIAAAAAjVwAADuKAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoFOG5JCHDYGYACCWAhUCYM8EQwKgegwgdA5C4NaABKBeAE2AiQDhzAEIAWCdAcgDIJJG1F+FdwYN3AeQFB+677abITtcRB8qCaK0k06uOD/rwlqyNg/1gG4OUtEGEGmirCEmqCnVGr8zsRmprTwyRyCfbliCOmQx9q6Mj5be/suy4CgRfxSwkp8rM+rmfWO0aAxlI/2bxhtsYiy9ZR3ZZiGPUfJ5eLCH0Og40B+5lS4+JZbREd3WtkRGvskl+f/s3v+f1b32tUPREaEUgQoBBjJsfAljRyMLk4N8XP7extjgFQJkkYTgjWLlAqleiNzwEBCpAY4YhuwTVIYgoyRGyKbgIgB0iHoB8XA+OZ8Ou2bGY00gAJL9liSUY6TeDNLnPx/QJA9Ln
 [...]
+  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, 
U+FE2E-FE2F;
+}
+/* cyrillic */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAACWcABIAAAAAWLAAACU5AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmobllYcNgZgAIIECFQJgzwRDAqBgWzzRAuCEAASgRQBNgIkA4QcBCAFgnQHIAyCSRtATxVsXGWGjQMMs+lnUBRVo81EUaPVpDXB/1+TmzJwD1T/qiCyZNisrEoqJdLUU4XdGFQhjzBlqe+erlaQaExxJzlQcKB465SpoPV52dI8GZeWGJIUaZVuemk76uNVowWj6Dl7XlNSpinpy1R//+CHMHBkVqDYZD5CSx/xEkR2/Fe927Mz/wxHZgogFOLL3jllJCU50T//nvXnJqmmwkDFJoWYDqR2oHRFf+0+Gd/y12qA5tatRDKsgSA2VhxVNl2DFql2TqkeY8jIjTIP+o4HxoNBSIVEjciRBq+PVWu2e4RzCU8YpmLECyEJFPCpR2O2y4d/ni
 [...]
+  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
+}
+/* greek-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAAXMABIAAAAACeAAAAVwAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANAhUCYM8EQwKg2iDSgsQABIUATYCJAMcBCAFgnQHIAyCSRt8CAieB2WbnmbLuYAwwpK8+iIe4P3r89wHDZaakNWCmB8R66SEWr+ILhpijnTqf6QAyyF8GVAOAPOWtmNg6llFXANTaQXCgXMubThOj6JRPCJsEWW3o1/4wX411uruvta/9FF8Zz50qenu3hVxmf4QIi1dRSzhkcR0SqA1QoiwzI2uAUbffgtBpA0YCssEQRChiaaAgMpAFvDsmKQshIEEer1l/u1J0Sbi8P6OJsQc3VHd6N0nlHe1MAhFbvPNcXJVWKNNekPqCYVx/lj8nqMi5BY4Pd6hectSY5E2Lll8SMf/HJXfEKEOfCtEMjEFBEHtpSkbjBK4aB1MIE
 [...]
+  unicode-range: U+1F00-1FFF;
+}
+/* greek */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABvIABIAAAAAOYgAABtmAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbjEocNgZgAIFkCFQJgzwRDArPdMcZC4FIABJwATYCJAODDAQgBYJ0ByAMgkkbLzMV3Bg3cB5AgtL+dFGUC8ojwf9fE9SQsQftHoablcBAJCnZiWWrVQuV5mlVJ2ZKaJa1O4xgpZOeStdtJqxoMWTv3rvjdJiEUBrhQCzjWKrrzr+v3IEvgtjCHD1r8RMqj2DUbHUyl4hbe5lIDkAEEv7BTsC+xxGuHLLDJzwiHqGlj3jhedKj/3NHyYLOPksVyBbSB1V0wvzv2n/ewGQCNDPJ4CNcyi6XXCtkT9WCK7lfZQjUdwVhSH0hX5Qr6naI5na/NTmQyDBHdEm3iAEoMEJG1gSjB2IwqiywRvWIHoLRPK+/h3l+b/sICQgQDouxxGMEJJh57K
 [...]
+  unicode-range: U+0370-03FF;
+}
+/* vietnamese */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABW4ABIAAAAANeQAABVYAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGjQbhlocNgZgAIEACFQJgzwRDArNRMZyC4IWABKBFAE2AiQDhCgEIAWCdAcgDIJJG0QwsxE2bBxAgN2rQPJ/ODCHzPnAWwWN2o42Fh2ljaWNtCCX3HjNpZ/jxeLZb4tm/kHiZ77mziCxZzy0cd8wTRJCiqDsSRqOR0gyC8+j3ffnZpLMGvMWRPfZ/87uBFagisZuqfzAb7P3+QVYiFknMxMjYpGImbB2t2HH1kadsmRrWXFGrkqX5TLxP6cqy2soa6trO4GdCmCmXToDmCtuKXj/ZyBcBEwQ3fvOvtv7qRSwgAQ4mq6lFACOaaw0uy1ldv9zuuKQSO46+Dl0Do9Oylz/M5dCGNyOU6+ueMEx1eTggIMuIVsO8utrIbVMv07ZhkxjhvHZUs
 [...]
+  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, 
U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, 
U+0329, U+1EA0-1EF9, U+20AB;
+}
+/* latin-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAC5gABIAAAAAcywAAC36AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGkAbjgwcgTAGYACDFAhUCYM8EQwKgbckgaVCC4N6ABKCCAE2AiQDh3AEIAWCdAcgDIJJGxxnJWybRvHgPADRiPpto6hJe1QiimDjIEDErxz8/+fkZAyBOmNq3n64RJGVYTsuMvUITcoKDzKbnypbeOMbTMui6C1taW9RKNHcVufFfHmORoTFgPXPgSnw9b5+VMOftv6L4lsP7Nfim5v2Fg/56vZtj9Xi2X1oL6wcCiUVkSRoowcKbqtiCxv72hEa+ySXh8iOvlc9XT27H+cQIKJzkEqRldoRFJE77dfP5dv9SY4YVAl4fHV0YXyVAjauylb1hue32fuUFViBOF1ahVEzCqsHioGKGBg5nZvTKYoJ6sSq6UQbF4o9l+mqzt3O2voMgP//fv
 [...]
+  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, 
U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAD2AABIAAAAAjnQAAD0aAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbmWQchV4GYACDIAhUCYM8EQwKgdx8gcR7C4QKABKCEAE2AiQDiBAEIAWCdAcgDIJJGzN/JezYiwK6AzihqSaqkQj7NFrlfHQg9jiQuO4X/P/nBM1EBrn5JK11TkWFUIRFnUFrFNvrPcp4DjlYevVgA0nxppzrUq2UwfojRitCYK27fdpSUHxF/dDCWlx/V1u8Guv6n+CPBeCi/9HtCEOUiBJRQoED6JkYbb+j7GNtuz+jRvSEZ/S00A7a2OhRipW6qzPAnRzRiJOHcO0f/0wy2b1bAsXMrrbsmBUhK0BVxx9efp7f5p/73qPEAETsPwy00f6KxdJqDIyKVRq5FmPZzFW5bKs2e9nKAG2zQ0Rdq2ivdNPVuxmRGFE4CwsLG8FAULHABE
 [...]
+  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, 
U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, 
U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+</style><g id="shape-2d5b5ebd-d89e-8002-8003-bc35b0c36344"><defs><clipPath 
class="frame-clip-def frame-clip" 
id="frame-clip-2d5b5ebd-d89e-8002-8003-bc35b0c36344-rumext-id-21"><rect rx="0" 
ry="0" x="0" y="0" width="480" height="360" transform="matrix(1.000000, 
0.000000, 0.000000, 1.000000, 0.000000, 0.000000)"/></clipPath></defs><g 
clip-path="url(#frame-clip-2d5b5ebd-d89e-8002-8003-bc35b0c36344-rumext-id-21)" 
fill="none"><clipPath class="frame-clip-def frame-clip" 
id="frame-clip-2d5b5ebd- [...]
\ No newline at end of file
diff --git a/contrib/svg/backend-unreachable.svg 
b/contrib/svg/backend-unreachable.svg
new file mode 100644
index 0000000..95ccfb8
--- /dev/null
+++ b/contrib/svg/backend-unreachable.svg
@@ -0,0 +1,126 @@
+<svg xmlns:xlink="http://www.w3.org/1999/xlink"; width="480" 
xmlns="http://www.w3.org/2000/svg"; height="360" 
id="screenshot-2d5b5ebd-d89e-8002-8003-bc3446c736f9" viewBox="0 0 480 360" 
style="-webkit-print-color-adjust: exact;" fill="none" version="1.1"><style 
data-loading="false">@font-face {
+    font-family: 'sourcesanspro';
+    font-style: normal;
+    font-weight: 400;
+    font-display: block;
+    src: 
url(data:font/woff;base64,d09GRgABAAAAAHSMABQAAAABDCAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQVNFAAABvAAAAD4AAABQinOTf0ZGVE0AAAH8AAAAHAAAABxwkYDFR0RFRgAAAhgAAAAiAAAAJgAnARBHUE9TAAACPAAACzwAADXwmf/bv0dTVUIAAA14AAAA+gAAAa7khdupT1MvMgAADnQAAABXAAAAYGdamnRjbWFwAAAOzAAAAYkAAAHiSESmoGN2dCAAABBYAAAAVgAAAFYUww7lZnBnbQAAELAAAAGxAAACZVO0L6dnYXNwAAASZAAAAAgAAAAIAAAAEGdseWYAABJsAABQOgAAm1B0O5TbaGVhZAAAYqgAAAAxAAAANgkVq9doaGVhAABi3AAAAB8AAAAkDmAFi2htdHgAAGL8AAACOgAAA6h47lnNbG9jYQAAZTgAAAHIAAAB1smHp
 [...]
+  }
+/* cyrillic-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAADvwABIAAAAAjVwAADuKAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoFOG5JCHDYGYACCWAhUCYM8EQwKgegwgdA5C4NaABKBeAE2AiQDhzAEIAWCdAcgDIJJG1F+FdwYN3AeQFB+677abITtcRB8qCaK0k06uOD/rwlqyNg/1gG4OUtEGEGmirCEmqCnVGr8zsRmprTwyRyCfbliCOmQx9q6Mj5be/suy4CgRfxSwkp8rM+rmfWO0aAxlI/2bxhtsYiy9ZR3ZZiGPUfJ5eLCH0Og40B+5lS4+JZbREd3WtkRGvskl+f/s3v+f1b32tUPREaEUgQoBBjJsfAljRyMLk4N8XP7extjgFQJkkYTgjWLlAqleiNzwEBCpAY4YhuwTVIYgoyRGyKbgIgB0iHoB8XA+OZ8Ou2bGY00gAJL9liSUY6TeDNLnPx/QJA9Ln
 [...]
+  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, 
U+FE2E-FE2F;
+}
+/* cyrillic */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAACWcABIAAAAAWLAAACU5AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmobllYcNgZgAIIECFQJgzwRDAqBgWzzRAuCEAASgRQBNgIkA4QcBCAFgnQHIAyCSRtATxVsXGWGjQMMs+lnUBRVo81EUaPVpDXB/1+TmzJwD1T/qiCyZNisrEoqJdLUU4XdGFQhjzBlqe+erlaQaExxJzlQcKB465SpoPV52dI8GZeWGJIUaZVuemk76uNVowWj6Dl7XlNSpinpy1R//+CHMHBkVqDYZD5CSx/xEkR2/Fe927Mz/wxHZgogFOLL3jllJCU50T//nvXnJqmmwkDFJoWYDqR2oHRFf+0+Gd/y12qA5tatRDKsgSA2VhxVNl2DFql2TqkeY8jIjTIP+o4HxoNBSIVEjciRBq+PVWu2e4RzCU8YpmLECyEJFPCpR2O2y4d/ni
 [...]
+  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
+}
+/* greek-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAAXMABIAAAAACeAAAAVwAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANAhUCYM8EQwKg2iDSgsQABIUATYCJAMcBCAFgnQHIAyCSRt8CAieB2WbnmbLuYAwwpK8+iIe4P3r89wHDZaakNWCmB8R66SEWr+ILhpijnTqf6QAyyF8GVAOAPOWtmNg6llFXANTaQXCgXMubThOj6JRPCJsEWW3o1/4wX411uruvta/9FF8Zz50qenu3hVxmf4QIi1dRSzhkcR0SqA1QoiwzI2uAUbffgtBpA0YCssEQRChiaaAgMpAFvDsmKQshIEEer1l/u1J0Sbi8P6OJsQc3VHd6N0nlHe1MAhFbvPNcXJVWKNNekPqCYVx/lj8nqMi5BY4Pd6hectSY5E2Lll8SMf/HJXfEKEOfCtEMjEFBEHtpSkbjBK4aB1MIE
 [...]
+  unicode-range: U+1F00-1FFF;
+}
+/* greek */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABvIABIAAAAAOYgAABtmAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbjEocNgZgAIFkCFQJgzwRDArPdMcZC4FIABJwATYCJAODDAQgBYJ0ByAMgkkbLzMV3Bg3cB5AgtL+dFGUC8ojwf9fE9SQsQftHoablcBAJCnZiWWrVQuV5mlVJ2ZKaJa1O4xgpZOeStdtJqxoMWTv3rvjdJiEUBrhQCzjWKrrzr+v3IEvgtjCHD1r8RMqj2DUbHUyl4hbe5lIDkAEEv7BTsC+xxGuHLLDJzwiHqGlj3jhedKj/3NHyYLOPksVyBbSB1V0wvzv2n/ewGQCNDPJ4CNcyi6XXCtkT9WCK7lfZQjUdwVhSH0hX5Qr6naI5na/NTmQyDBHdEm3iAEoMEJG1gSjB2IwqiywRvWIHoLRPK+/h3l+b/sICQgQDouxxGMEJJh57K
 [...]
+  unicode-range: U+0370-03FF;
+}
+/* vietnamese */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABW4ABIAAAAANeQAABVYAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGjQbhlocNgZgAIEACFQJgzwRDArNRMZyC4IWABKBFAE2AiQDhCgEIAWCdAcgDIJJG0QwsxE2bBxAgN2rQPJ/ODCHzPnAWwWN2o42Fh2ljaWNtCCX3HjNpZ/jxeLZb4tm/kHiZ77mziCxZzy0cd8wTRJCiqDsSRqOR0gyC8+j3ffnZpLMGvMWRPfZ/87uBFagisZuqfzAb7P3+QVYiFknMxMjYpGImbB2t2HH1kadsmRrWXFGrkqX5TLxP6cqy2soa6trO4GdCmCmXToDmCtuKXj/ZyBcBEwQ3fvOvtv7qRSwgAQ4mq6lFACOaaw0uy1ldv9zuuKQSO46+Dl0Do9Oylz/M5dCGNyOU6+ueMEx1eTggIMuIVsO8utrIbVMv07ZhkxjhvHZUs
 [...]
+  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, 
U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, 
U+0329, U+1EA0-1EF9, U+20AB;
+}
+/* latin-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAC5gABIAAAAAcywAAC36AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGkAbjgwcgTAGYACDFAhUCYM8EQwKgbckgaVCC4N6ABKCCAE2AiQDh3AEIAWCdAcgDIJJGxxnJWybRvHgPADRiPpto6hJe1QiimDjIEDErxz8/+fkZAyBOmNq3n64RJGVYTsuMvUITcoKDzKbnypbeOMbTMui6C1taW9RKNHcVufFfHmORoTFgPXPgSnw9b5+VMOftv6L4lsP7Nfim5v2Fg/56vZtj9Xi2X1oL6wcCiUVkSRoowcKbqtiCxv72hEa+ySXh8iOvlc9XT27H+cQIKJzkEqRldoRFJE77dfP5dv9SY4YVAl4fHV0YXyVAjauylb1hue32fuUFViBOF1ahVEzCqsHioGKGBg5nZvTKYoJ6sSq6UQbF4o9l+mqzt3O2voMgP//fv
 [...]
+  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, 
U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAD2AABIAAAAAjnQAAD0aAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbmWQchV4GYACDIAhUCYM8EQwKgdx8gcR7C4QKABKCEAE2AiQDiBAEIAWCdAcgDIJJGzN/JezYiwK6AzihqSaqkQj7NFrlfHQg9jiQuO4X/P/nBM1EBrn5JK11TkWFUIRFnUFrFNvrPcp4DjlYevVgA0nxppzrUq2UwfojRitCYK27fdpSUHxF/dDCWlx/V1u8Guv6n+CPBeCi/9HtCEOUiBJRQoED6JkYbb+j7GNtuz+jRvSEZ/S00A7a2OhRipW6qzPAnRzRiJOHcO0f/0wy2b1bAsXMrrbsmBUhK0BVxx9efp7f5p/73qPEAETsPwy00f6KxdJqDIyKVRq5FmPZzFW5bKs2e9nKAG2zQ0Rdq2ivdNPVuxmRGFE4CwsLG8FAULHABE
 [...]
+  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, 
U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, 
U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+
+/* cyrillic-ext */
+@font-face {
+  font-family: 'JetBrains Mono';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAARsABAAAAAACMwAAAQRAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhwbHhwoBmA/U1RBVF4AXBEICoRkg3oLGgABNgIkAy4EIAWFAAeBAwwHGy8HyI7Cca8UYSlFWGJzMUTEQ/1+r2f33Q+oAgAFVkiO0LMiG92pzNTWmEogIUHV6LrA3+vU9yUZFWCUyyYpAGzHxMo5cgl5YpzSCUM8NWtp6sXT3zttbOqD96hLoIAijvawNWhs2hMogzEXBdQFssAy6shdkO6VPDXsvEGgCwihJoRAvaBtQgx0vqymBYQK7HoBasgsSYO9G/Rcy7nAD9pML9mFjgKPfId1ALiW9o7HQAUNkLR49NmAP3T1LIDvcKYsVP8XB0G1hXJmAH2cGQG5lOOYwRNCU2IAjgXYW7OFQ8CTV1oH8oewJAxfJWQEAAQqZBDoKEB+BpBwZj
 [...]
+  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, 
U+FE2E-FE2F;
+}
+/* cyrillic */
+@font-face {
+  font-family: 'JetBrains Mono';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABSoABAAAAAALZwAABRHAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoEUG4JCHIFaBmA/U1RBVF4AgjQRCAq6aK19C4IEAAE2AiQDg3gEIAWFAAeIdgwHGxUlFeOYJbBxAI/ZefqIqs3iiv8/Jchx1MK1Hj6QCjtsqbzREj7Uu8Vx4pSRrqjmog/tOGN3PfRXFIaNPCUhbk3yIME013ZitMnf2OPLamGnvJSoHMue4TQeqDV+b/f2ixpqiWQm3a2TaXSGZBIKQzTpane0ls7s7gPdE1EA4QKMMiqqbEyFrGs1kCcjOjxu6582F5E4AxChZTD2BkxKGCX4gI1UsRK9DL0of1R4P9u7+5HGfrX3OwbnhVDfo1ShNOG0//9r5nsDbebe/2ezwChUT4Wa4SIYk9iMLSXbsgQUHjkAHhu73EgVO0u+qBHYhiz4TghZsf
 [...]
+  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
+}
+/* greek */
+@font-face {
+  font-family: 'JetBrains Mono';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABB4ABAAAAAAI2AAABAXAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGnwbHhyBWgZgP1NUQVReAIFKEQgKq3yjDQuBYAABNgIkA4M4BCAFhQAHhzAMBxv5HLOiTpNW7pD9lwvchIG1Lpgw0C5JhmaFsVEsKmGKMewlOrSU5cmvTnzOOQPGOx3KexV+GN3p0I93joDyL/qeeXt0BDFUBEagIjOEkEIR5Ojui1s7f69T3/syhYBMCpCJ5SQmUGyd8w2SCwhTeSzfDivgXB4L/dP9b+aefZ9fu0QhJFwc6AOwtOFxW/+0uWv0fyuJlkEvihEWc/aATS4ygqvW30H808Xe/L0SjiMo4e2gXehKDiTXjI87mldKHlwBxMd4sEhn7sqnhxmdzQoANgUVjcjWIxZVSG6lNuT/AECddMg+31pq79/clMEFyEa4pCpOV83szt
 [...]
+  unicode-range: U+0370-03FF;
+}
+/* vietnamese */
+@font-face {
+  font-family: 'JetBrains Mono';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAA8AABAAAAAALJAAAA6fAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGnYbhWocghYGYD9TVEFUXgCCbBEICrBAp2wLgjIAATYCJAOEHAQgBYUAB4w9DAcb7SUzo3aUk7oOwf/hwBQZJp2w6h8GxJG6TTswGCNFVinYG8lm36Y5Wwrq620Hiodu88UWwvRjNBxCLu1AUZ8j17L3P6mDsd5az9cxHp7f339r7/M+PEpkgpHMPJOUXX+bSVOSEAGEJN6fp23fn2EMdGmjoA1kUAQbELhUiyI8TGy0iTdWYLId4d/gRxfCGJMpWvToat1c/ZQ+xAAoS9OhRa/Y4//zpbk3ubZ/W16va0fs5+wHACEzOtuzGztAp6kDhqyuUIjnnxQIGiktsqW1oS8KpLTtPHrpuOaMT619aaen+x1P7s+xCh/JFa53Wd4aH3Wqfw/0QP
 [...]
+  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, 
U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, 
U+0329, U+1EA0-1EF9, U+20AB;
+}
+/* latin-ext */
+@font-face {
+  font-family: 'JetBrains Mono';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABukABAAAAAAS6AAABtCAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoIkG4ksHIMyBmA/U1RBVF4AhGYRCArddMwQC4NuAAE2AiQDhx4EIAWFAAeQVwwHG7M/BdzxsHHAYHB5TVFULQLJ/9fkxhhag2p1D3qSvMiMZHVWrza7ig2lYchKm4FzGC/zgrUkjl1wOOguDsaFfM0Py8lyv5LAwHlihZv4JDR+r8HtyMosTVjuERr7JJeHf8bx3ve+lYgGaHJy/XlLC2VVdYvLO0twSVJUg3+e31Z/Llhg1ZQYCComCP14vPcQRUDBpyg+icHGKKadaSed2Wknqp2K7WbbmXV3/X8zBen/xCR3XrC+0kS1QsPtL81VyXS6kMwcIap7i4VdPmL9z63t2kdUqAA1q0P+n+dk920jiTTjmDo+DjiMvPP//3sXdeJEY0yzAG
 [...]
+  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, 
U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+  font-family: 'JetBrains Mono';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAFJgABAAAAAA4hAAAFH8AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoEUG4ZQHIGacgZgP1NUQVReAIUqEQgKgdxkgaxNC4YYAAE2AiQDjB4EIAWFAAejFgwHG8fFB8Tb90hAdwCkblfXTo1ECBsHAbDjs2cGgo0TQOB5yP7/vyeoMYbwbgcoNqtpIlQEYUlYElazCmph0RVdm7qIwk/shy9ruey0yhG+ZKISeRi+GSzGzpPpeIHb7aD8PEtS/nHRORqGOrrXBlt2Uv13SNhhl6tnqYhoMTMZfDVYKOxRfM2jMIYO7kb//JsujEx5ydtdvhfQdr9rlu+SEwkSHZ881orhYxO3PlFyNWC3YEvozY2nxfNzNvt+jBQ8Ff8ED3gFPUowOcRyXDAJIlJTpS5GoO/b763q9o9mzSoLJByQMKtzolbptQ6NB9TAM68f8f
 [...]
+  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, 
U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, 
U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+</style><g id="shape-2d5b5ebd-d89e-8002-8003-bc3446c736f9"><defs><clipPath 
class="frame-clip-def frame-clip" 
id="frame-clip-2d5b5ebd-d89e-8002-8003-bc3446c736f9-rumext-id-46"><rect rx="0" 
ry="0" x="0" y="0" width="480" height="360" transform="matrix(1.000000, 
0.000000, 0.000000, 1.000000, 0.000000, 0.000000)"/></clipPath></defs><g 
clip-path="url(#frame-clip-2d5b5ebd-d89e-8002-8003-bc3446c736f9-rumext-id-46)" 
fill="none"><clipPath class="frame-clip-def frame-clip" 
id="frame-clip-2d5b5ebd- [...]
\ No newline at end of file
diff --git a/contrib/svg/backend-x509-cert-bad.svg 
b/contrib/svg/backend-x509-cert-bad.svg
new file mode 100644
index 0000000..bf9ee2b
--- /dev/null
+++ b/contrib/svg/backend-x509-cert-bad.svg
@@ -0,0 +1,71 @@
+<svg xmlns:xlink="http://www.w3.org/1999/xlink"; width="480" 
xmlns="http://www.w3.org/2000/svg"; height="360" 
id="screenshot-2d5b5ebd-d89e-8002-8003-bc361a39c911" viewBox="0 0 480 360" 
style="-webkit-print-color-adjust: exact;" fill="none" version="1.1"><style 
data-loading="false">@font-face {
+    font-family: 'sourcesanspro';
+    font-style: normal;
+    font-weight: 400;
+    font-display: block;
+    src: 
url(data:font/woff;base64,d09GRgABAAAAAHSMABQAAAABDCAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQVNFAAABvAAAAD4AAABQinOTf0ZGVE0AAAH8AAAAHAAAABxwkYDFR0RFRgAAAhgAAAAiAAAAJgAnARBHUE9TAAACPAAACzwAADXwmf/bv0dTVUIAAA14AAAA+gAAAa7khdupT1MvMgAADnQAAABXAAAAYGdamnRjbWFwAAAOzAAAAYkAAAHiSESmoGN2dCAAABBYAAAAVgAAAFYUww7lZnBnbQAAELAAAAGxAAACZVO0L6dnYXNwAAASZAAAAAgAAAAIAAAAEGdseWYAABJsAABQOgAAm1B0O5TbaGVhZAAAYqgAAAAxAAAANgkVq9doaGVhAABi3AAAAB8AAAAkDmAFi2htdHgAAGL8AAACOgAAA6h47lnNbG9jYQAAZTgAAAHIAAAB1smHp
 [...]
+  }
+/* cyrillic-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAADvwABIAAAAAjVwAADuKAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoFOG5JCHDYGYACCWAhUCYM8EQwKgegwgdA5C4NaABKBeAE2AiQDhzAEIAWCdAcgDIJJG1F+FdwYN3AeQFB+677abITtcRB8qCaK0k06uOD/rwlqyNg/1gG4OUtEGEGmirCEmqCnVGr8zsRmprTwyRyCfbliCOmQx9q6Mj5be/suy4CgRfxSwkp8rM+rmfWO0aAxlI/2bxhtsYiy9ZR3ZZiGPUfJ5eLCH0Og40B+5lS4+JZbREd3WtkRGvskl+f/s3v+f1b32tUPREaEUgQoBBjJsfAljRyMLk4N8XP7extjgFQJkkYTgjWLlAqleiNzwEBCpAY4YhuwTVIYgoyRGyKbgIgB0iHoB8XA+OZ8Ou2bGY00gAJL9liSUY6TeDNLnPx/QJA9Ln
 [...]
+  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, 
U+FE2E-FE2F;
+}
+/* cyrillic */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAACWcABIAAAAAWLAAACU5AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmobllYcNgZgAIIECFQJgzwRDAqBgWzzRAuCEAASgRQBNgIkA4QcBCAFgnQHIAyCSRtATxVsXGWGjQMMs+lnUBRVo81EUaPVpDXB/1+TmzJwD1T/qiCyZNisrEoqJdLUU4XdGFQhjzBlqe+erlaQaExxJzlQcKB465SpoPV52dI8GZeWGJIUaZVuemk76uNVowWj6Dl7XlNSpinpy1R//+CHMHBkVqDYZD5CSx/xEkR2/Fe927Mz/wxHZgogFOLL3jllJCU50T//nvXnJqmmwkDFJoWYDqR2oHRFf+0+Gd/y12qA5tatRDKsgSA2VhxVNl2DFql2TqkeY8jIjTIP+o4HxoNBSIVEjciRBq+PVWu2e4RzCU8YpmLECyEJFPCpR2O2y4d/ni
 [...]
+  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
+}
+/* greek-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAAXMABIAAAAACeAAAAVwAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANAhUCYM8EQwKg2iDSgsQABIUATYCJAMcBCAFgnQHIAyCSRt8CAieB2WbnmbLuYAwwpK8+iIe4P3r89wHDZaakNWCmB8R66SEWr+ILhpijnTqf6QAyyF8GVAOAPOWtmNg6llFXANTaQXCgXMubThOj6JRPCJsEWW3o1/4wX411uruvta/9FF8Zz50qenu3hVxmf4QIi1dRSzhkcR0SqA1QoiwzI2uAUbffgtBpA0YCssEQRChiaaAgMpAFvDsmKQshIEEer1l/u1J0Sbi8P6OJsQc3VHd6N0nlHe1MAhFbvPNcXJVWKNNekPqCYVx/lj8nqMi5BY4Pd6hectSY5E2Lll8SMf/HJXfEKEOfCtEMjEFBEHtpSkbjBK4aB1MIE
 [...]
+  unicode-range: U+1F00-1FFF;
+}
+/* greek */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABvIABIAAAAAOYgAABtmAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbjEocNgZgAIFkCFQJgzwRDArPdMcZC4FIABJwATYCJAODDAQgBYJ0ByAMgkkbLzMV3Bg3cB5AgtL+dFGUC8ojwf9fE9SQsQftHoablcBAJCnZiWWrVQuV5mlVJ2ZKaJa1O4xgpZOeStdtJqxoMWTv3rvjdJiEUBrhQCzjWKrrzr+v3IEvgtjCHD1r8RMqj2DUbHUyl4hbe5lIDkAEEv7BTsC+xxGuHLLDJzwiHqGlj3jhedKj/3NHyYLOPksVyBbSB1V0wvzv2n/ewGQCNDPJ4CNcyi6XXCtkT9WCK7lfZQjUdwVhSH0hX5Qr6naI5na/NTmQyDBHdEm3iAEoMEJG1gSjB2IwqiywRvWIHoLRPK+/h3l+b/sICQgQDouxxGMEJJh57K
 [...]
+  unicode-range: U+0370-03FF;
+}
+/* vietnamese */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABW4ABIAAAAANeQAABVYAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGjQbhlocNgZgAIEACFQJgzwRDArNRMZyC4IWABKBFAE2AiQDhCgEIAWCdAcgDIJJG0QwsxE2bBxAgN2rQPJ/ODCHzPnAWwWN2o42Fh2ljaWNtCCX3HjNpZ/jxeLZb4tm/kHiZ77mziCxZzy0cd8wTRJCiqDsSRqOR0gyC8+j3ffnZpLMGvMWRPfZ/87uBFagisZuqfzAb7P3+QVYiFknMxMjYpGImbB2t2HH1kadsmRrWXFGrkqX5TLxP6cqy2soa6trO4GdCmCmXToDmCtuKXj/ZyBcBEwQ3fvOvtv7qRSwgAQ4mq6lFACOaaw0uy1ldv9zuuKQSO46+Dl0Do9Oylz/M5dCGNyOU6+ueMEx1eTggIMuIVsO8utrIbVMv07ZhkxjhvHZUs
 [...]
+  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, 
U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, 
U+0329, U+1EA0-1EF9, U+20AB;
+}
+/* latin-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAC5gABIAAAAAcywAAC36AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGkAbjgwcgTAGYACDFAhUCYM8EQwKgbckgaVCC4N6ABKCCAE2AiQDh3AEIAWCdAcgDIJJGxxnJWybRvHgPADRiPpto6hJe1QiimDjIEDErxz8/+fkZAyBOmNq3n64RJGVYTsuMvUITcoKDzKbnypbeOMbTMui6C1taW9RKNHcVufFfHmORoTFgPXPgSnw9b5+VMOftv6L4lsP7Nfim5v2Fg/56vZtj9Xi2X1oL6wcCiUVkSRoowcKbqtiCxv72hEa+ySXh8iOvlc9XT27H+cQIKJzkEqRldoRFJE77dfP5dv9SY4YVAl4fHV0YXyVAjauylb1hue32fuUFViBOF1ahVEzCqsHioGKGBg5nZvTKYoJ6sSq6UQbF4o9l+mqzt3O2voMgP//fv
 [...]
+  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, 
U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAD2AABIAAAAAjnQAAD0aAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbmWQchV4GYACDIAhUCYM8EQwKgdx8gcR7C4QKABKCEAE2AiQDiBAEIAWCdAcgDIJJGzN/JezYiwK6AzihqSaqkQj7NFrlfHQg9jiQuO4X/P/nBM1EBrn5JK11TkWFUIRFnUFrFNvrPcp4DjlYevVgA0nxppzrUq2UwfojRitCYK27fdpSUHxF/dDCWlx/V1u8Guv6n+CPBeCi/9HtCEOUiBJRQoED6JkYbb+j7GNtuz+jRvSEZ/S00A7a2OhRipW6qzPAnRzRiJOHcO0f/0wy2b1bAsXMrrbsmBUhK0BVxx9efp7f5p/73qPEAETsPwy00f6KxdJqDIyKVRq5FmPZzFW5bKs2e9nKAG2zQ0Rdq2ivdNPVuxmRGFE4CwsLG8FAULHABE
 [...]
+  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, 
U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, 
U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+</style><g id="shape-2d5b5ebd-d89e-8002-8003-bc361a39c911"><defs><clipPath 
class="frame-clip-def frame-clip" 
id="frame-clip-2d5b5ebd-d89e-8002-8003-bc361a39c911-rumext-id-64"><rect rx="0" 
ry="0" x="0" y="0" width="480" height="360" transform="matrix(1.000000, 
0.000000, 0.000000, 1.000000, 0.000000, 0.000000)"/></clipPath></defs><g 
clip-path="url(#frame-clip-2d5b5ebd-d89e-8002-8003-bc361a39c911-rumext-id-64)" 
fill="none"><clipPath class="frame-clip-def frame-clip" 
id="frame-clip-2d5b5ebd- [...]
\ No newline at end of file
diff --git a/contrib/svg/child-died.svg b/contrib/svg/child-died.svg
new file mode 100644
index 0000000..5f7fe50
--- /dev/null
+++ b/contrib/svg/child-died.svg
@@ -0,0 +1,71 @@
+<svg xmlns:xlink="http://www.w3.org/1999/xlink"; width="480" 
xmlns="http://www.w3.org/2000/svg"; height="360" 
id="screenshot-2d5b5ebd-d89e-8002-8003-bc3908030f86" viewBox="0 0 480 360" 
style="-webkit-print-color-adjust: exact;" fill="none" version="1.1"><style 
data-loading="false">@font-face {
+    font-family: 'sourcesanspro';
+    font-style: normal;
+    font-weight: 400;
+    font-display: block;
+    src: 
url(data:font/woff;base64,d09GRgABAAAAAHSMABQAAAABDCAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQVNFAAABvAAAAD4AAABQinOTf0ZGVE0AAAH8AAAAHAAAABxwkYDFR0RFRgAAAhgAAAAiAAAAJgAnARBHUE9TAAACPAAACzwAADXwmf/bv0dTVUIAAA14AAAA+gAAAa7khdupT1MvMgAADnQAAABXAAAAYGdamnRjbWFwAAAOzAAAAYkAAAHiSESmoGN2dCAAABBYAAAAVgAAAFYUww7lZnBnbQAAELAAAAGxAAACZVO0L6dnYXNwAAASZAAAAAgAAAAIAAAAEGdseWYAABJsAABQOgAAm1B0O5TbaGVhZAAAYqgAAAAxAAAANgkVq9doaGVhAABi3AAAAB8AAAAkDmAFi2htdHgAAGL8AAACOgAAA6h47lnNbG9jYQAAZTgAAAHIAAAB1smHp
 [...]
+  }
+/* cyrillic-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAADvwABIAAAAAjVwAADuKAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoFOG5JCHDYGYACCWAhUCYM8EQwKgegwgdA5C4NaABKBeAE2AiQDhzAEIAWCdAcgDIJJG1F+FdwYN3AeQFB+677abITtcRB8qCaK0k06uOD/rwlqyNg/1gG4OUtEGEGmirCEmqCnVGr8zsRmprTwyRyCfbliCOmQx9q6Mj5be/suy4CgRfxSwkp8rM+rmfWO0aAxlI/2bxhtsYiy9ZR3ZZiGPUfJ5eLCH0Og40B+5lS4+JZbREd3WtkRGvskl+f/s3v+f1b32tUPREaEUgQoBBjJsfAljRyMLk4N8XP7extjgFQJkkYTgjWLlAqleiNzwEBCpAY4YhuwTVIYgoyRGyKbgIgB0iHoB8XA+OZ8Ou2bGY00gAJL9liSUY6TeDNLnPx/QJA9Ln
 [...]
+  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, 
U+FE2E-FE2F;
+}
+/* cyrillic */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAACWcABIAAAAAWLAAACU5AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmobllYcNgZgAIIECFQJgzwRDAqBgWzzRAuCEAASgRQBNgIkA4QcBCAFgnQHIAyCSRtATxVsXGWGjQMMs+lnUBRVo81EUaPVpDXB/1+TmzJwD1T/qiCyZNisrEoqJdLUU4XdGFQhjzBlqe+erlaQaExxJzlQcKB465SpoPV52dI8GZeWGJIUaZVuemk76uNVowWj6Dl7XlNSpinpy1R//+CHMHBkVqDYZD5CSx/xEkR2/Fe927Mz/wxHZgogFOLL3jllJCU50T//nvXnJqmmwkDFJoWYDqR2oHRFf+0+Gd/y12qA5tatRDKsgSA2VhxVNl2DFql2TqkeY8jIjTIP+o4HxoNBSIVEjciRBq+PVWu2e4RzCU8YpmLECyEJFPCpR2O2y4d/ni
 [...]
+  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
+}
+/* greek-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAAXMABIAAAAACeAAAAVwAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANAhUCYM8EQwKg2iDSgsQABIUATYCJAMcBCAFgnQHIAyCSRt8CAieB2WbnmbLuYAwwpK8+iIe4P3r89wHDZaakNWCmB8R66SEWr+ILhpijnTqf6QAyyF8GVAOAPOWtmNg6llFXANTaQXCgXMubThOj6JRPCJsEWW3o1/4wX411uruvta/9FF8Zz50qenu3hVxmf4QIi1dRSzhkcR0SqA1QoiwzI2uAUbffgtBpA0YCssEQRChiaaAgMpAFvDsmKQshIEEer1l/u1J0Sbi8P6OJsQc3VHd6N0nlHe1MAhFbvPNcXJVWKNNekPqCYVx/lj8nqMi5BY4Pd6hectSY5E2Lll8SMf/HJXfEKEOfCtEMjEFBEHtpSkbjBK4aB1MIE
 [...]
+  unicode-range: U+1F00-1FFF;
+}
+/* greek */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABvIABIAAAAAOYgAABtmAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbjEocNgZgAIFkCFQJgzwRDArPdMcZC4FIABJwATYCJAODDAQgBYJ0ByAMgkkbLzMV3Bg3cB5AgtL+dFGUC8ojwf9fE9SQsQftHoablcBAJCnZiWWrVQuV5mlVJ2ZKaJa1O4xgpZOeStdtJqxoMWTv3rvjdJiEUBrhQCzjWKrrzr+v3IEvgtjCHD1r8RMqj2DUbHUyl4hbe5lIDkAEEv7BTsC+xxGuHLLDJzwiHqGlj3jhedKj/3NHyYLOPksVyBbSB1V0wvzv2n/ewGQCNDPJ4CNcyi6XXCtkT9WCK7lfZQjUdwVhSH0hX5Qr6naI5na/NTmQyDBHdEm3iAEoMEJG1gSjB2IwqiywRvWIHoLRPK+/h3l+b/sICQgQDouxxGMEJJh57K
 [...]
+  unicode-range: U+0370-03FF;
+}
+/* vietnamese */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABW4ABIAAAAANeQAABVYAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGjQbhlocNgZgAIEACFQJgzwRDArNRMZyC4IWABKBFAE2AiQDhCgEIAWCdAcgDIJJG0QwsxE2bBxAgN2rQPJ/ODCHzPnAWwWN2o42Fh2ljaWNtCCX3HjNpZ/jxeLZb4tm/kHiZ77mziCxZzy0cd8wTRJCiqDsSRqOR0gyC8+j3ffnZpLMGvMWRPfZ/87uBFagisZuqfzAb7P3+QVYiFknMxMjYpGImbB2t2HH1kadsmRrWXFGrkqX5TLxP6cqy2soa6trO4GdCmCmXToDmCtuKXj/ZyBcBEwQ3fvOvtv7qRSwgAQ4mq6lFACOaaw0uy1ldv9zuuKQSO46+Dl0Do9Oylz/M5dCGNyOU6+ueMEx1eTggIMuIVsO8utrIbVMv07ZhkxjhvHZUs
 [...]
+  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, 
U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, 
U+0329, U+1EA0-1EF9, U+20AB;
+}
+/* latin-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAC5gABIAAAAAcywAAC36AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGkAbjgwcgTAGYACDFAhUCYM8EQwKgbckgaVCC4N6ABKCCAE2AiQDh3AEIAWCdAcgDIJJGxxnJWybRvHgPADRiPpto6hJe1QiimDjIEDErxz8/+fkZAyBOmNq3n64RJGVYTsuMvUITcoKDzKbnypbeOMbTMui6C1taW9RKNHcVufFfHmORoTFgPXPgSnw9b5+VMOftv6L4lsP7Nfim5v2Fg/56vZtj9Xi2X1oL6wcCiUVkSRoowcKbqtiCxv72hEa+ySXh8iOvlc9XT27H+cQIKJzkEqRldoRFJE77dfP5dv9SY4YVAl4fHV0YXyVAjauylb1hue32fuUFViBOF1ahVEzCqsHioGKGBg5nZvTKYoJ6sSq6UQbF4o9l+mqzt3O2voMgP//fv
 [...]
+  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, 
U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAD2AABIAAAAAjnQAAD0aAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbmWQchV4GYACDIAhUCYM8EQwKgdx8gcR7C4QKABKCEAE2AiQDiBAEIAWCdAcgDIJJGzN/JezYiwK6AzihqSaqkQj7NFrlfHQg9jiQuO4X/P/nBM1EBrn5JK11TkWFUIRFnUFrFNvrPcp4DjlYevVgA0nxppzrUq2UwfojRitCYK27fdpSUHxF/dDCWlx/V1u8Guv6n+CPBeCi/9HtCEOUiBJRQoED6JkYbb+j7GNtuz+jRvSEZ/S00A7a2OhRipW6qzPAnRzRiJOHcO0f/0wy2b1bAsXMrrbsmBUhK0BVxx9efp7f5p/73qPEAETsPwy00f6KxdJqDIyKVRq5FmPZzFW5bKs2e9nKAG2zQ0Rdq2ivdNPVuxmRGFE4CwsLG8FAULHABE
 [...]
+  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, 
U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, 
U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+</style><g id="shape-2d5b5ebd-d89e-8002-8003-bc3908030f86"><defs><clipPath 
class="frame-clip-def frame-clip" 
id="frame-clip-2d5b5ebd-d89e-8002-8003-bc3908030f86-rumext-id-55"><rect rx="0" 
ry="0" x="0" y="0" width="480" height="360" transform="matrix(1.000000, 
0.000000, 0.000000, 1.000000, 0.000000, 0.000000)"/></clipPath></defs><g 
clip-path="url(#frame-clip-2d5b5ebd-d89e-8002-8003-bc3908030f86-rumext-id-55)" 
fill="none"><clipPath class="frame-clip-def frame-clip" 
id="frame-clip-2d5b5ebd- [...]
\ No newline at end of file
diff --git a/contrib/svg/err-num-read-fail.svg 
b/contrib/svg/err-num-read-fail.svg
new file mode 100644
index 0000000..2e4f52b
--- /dev/null
+++ b/contrib/svg/err-num-read-fail.svg
@@ -0,0 +1,71 @@
+<svg xmlns:xlink="http://www.w3.org/1999/xlink"; width="480" 
xmlns="http://www.w3.org/2000/svg"; height="360" 
id="screenshot-7abbe548-0101-8074-8003-bc3c29bacfd3" viewBox="0 0 480 360" 
style="-webkit-print-color-adjust: exact;" fill="none" version="1.1"><style 
data-loading="false">@font-face {
+    font-family: 'sourcesanspro';
+    font-style: normal;
+    font-weight: 400;
+    font-display: block;
+    src: 
url(data:font/woff;base64,d09GRgABAAAAAHSMABQAAAABDCAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQVNFAAABvAAAAD4AAABQinOTf0ZGVE0AAAH8AAAAHAAAABxwkYDFR0RFRgAAAhgAAAAiAAAAJgAnARBHUE9TAAACPAAACzwAADXwmf/bv0dTVUIAAA14AAAA+gAAAa7khdupT1MvMgAADnQAAABXAAAAYGdamnRjbWFwAAAOzAAAAYkAAAHiSESmoGN2dCAAABBYAAAAVgAAAFYUww7lZnBnbQAAELAAAAGxAAACZVO0L6dnYXNwAAASZAAAAAgAAAAIAAAAEGdseWYAABJsAABQOgAAm1B0O5TbaGVhZAAAYqgAAAAxAAAANgkVq9doaGVhAABi3AAAAB8AAAAkDmAFi2htdHgAAGL8AAACOgAAA6h47lnNbG9jYQAAZTgAAAHIAAAB1smHp
 [...]
+  }
+/* cyrillic-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAADvwABIAAAAAjVwAADuKAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoFOG5JCHDYGYACCWAhUCYM8EQwKgegwgdA5C4NaABKBeAE2AiQDhzAEIAWCdAcgDIJJG1F+FdwYN3AeQFB+677abITtcRB8qCaK0k06uOD/rwlqyNg/1gG4OUtEGEGmirCEmqCnVGr8zsRmprTwyRyCfbliCOmQx9q6Mj5be/suy4CgRfxSwkp8rM+rmfWO0aAxlI/2bxhtsYiy9ZR3ZZiGPUfJ5eLCH0Og40B+5lS4+JZbREd3WtkRGvskl+f/s3v+f1b32tUPREaEUgQoBBjJsfAljRyMLk4N8XP7extjgFQJkkYTgjWLlAqleiNzwEBCpAY4YhuwTVIYgoyRGyKbgIgB0iHoB8XA+OZ8Ou2bGY00gAJL9liSUY6TeDNLnPx/QJA9Ln
 [...]
+  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, 
U+FE2E-FE2F;
+}
+/* cyrillic */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAACWcABIAAAAAWLAAACU5AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmobllYcNgZgAIIECFQJgzwRDAqBgWzzRAuCEAASgRQBNgIkA4QcBCAFgnQHIAyCSRtATxVsXGWGjQMMs+lnUBRVo81EUaPVpDXB/1+TmzJwD1T/qiCyZNisrEoqJdLUU4XdGFQhjzBlqe+erlaQaExxJzlQcKB465SpoPV52dI8GZeWGJIUaZVuemk76uNVowWj6Dl7XlNSpinpy1R//+CHMHBkVqDYZD5CSx/xEkR2/Fe927Mz/wxHZgogFOLL3jllJCU50T//nvXnJqmmwkDFJoWYDqR2oHRFf+0+Gd/y12qA5tatRDKsgSA2VhxVNl2DFql2TqkeY8jIjTIP+o4HxoNBSIVEjciRBq+PVWu2e4RzCU8YpmLECyEJFPCpR2O2y4d/ni
 [...]
+  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
+}
+/* greek-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAAXMABIAAAAACeAAAAVwAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANAhUCYM8EQwKg2iDSgsQABIUATYCJAMcBCAFgnQHIAyCSRt8CAieB2WbnmbLuYAwwpK8+iIe4P3r89wHDZaakNWCmB8R66SEWr+ILhpijnTqf6QAyyF8GVAOAPOWtmNg6llFXANTaQXCgXMubThOj6JRPCJsEWW3o1/4wX411uruvta/9FF8Zz50qenu3hVxmf4QIi1dRSzhkcR0SqA1QoiwzI2uAUbffgtBpA0YCssEQRChiaaAgMpAFvDsmKQshIEEer1l/u1J0Sbi8P6OJsQc3VHd6N0nlHe1MAhFbvPNcXJVWKNNekPqCYVx/lj8nqMi5BY4Pd6hectSY5E2Lll8SMf/HJXfEKEOfCtEMjEFBEHtpSkbjBK4aB1MIE
 [...]
+  unicode-range: U+1F00-1FFF;
+}
+/* greek */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABvIABIAAAAAOYgAABtmAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbjEocNgZgAIFkCFQJgzwRDArPdMcZC4FIABJwATYCJAODDAQgBYJ0ByAMgkkbLzMV3Bg3cB5AgtL+dFGUC8ojwf9fE9SQsQftHoablcBAJCnZiWWrVQuV5mlVJ2ZKaJa1O4xgpZOeStdtJqxoMWTv3rvjdJiEUBrhQCzjWKrrzr+v3IEvgtjCHD1r8RMqj2DUbHUyl4hbe5lIDkAEEv7BTsC+xxGuHLLDJzwiHqGlj3jhedKj/3NHyYLOPksVyBbSB1V0wvzv2n/ewGQCNDPJ4CNcyi6XXCtkT9WCK7lfZQjUdwVhSH0hX5Qr6naI5na/NTmQyDBHdEm3iAEoMEJG1gSjB2IwqiywRvWIHoLRPK+/h3l+b/sICQgQDouxxGMEJJh57K
 [...]
+  unicode-range: U+0370-03FF;
+}
+/* vietnamese */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABW4ABIAAAAANeQAABVYAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGjQbhlocNgZgAIEACFQJgzwRDArNRMZyC4IWABKBFAE2AiQDhCgEIAWCdAcgDIJJG0QwsxE2bBxAgN2rQPJ/ODCHzPnAWwWN2o42Fh2ljaWNtCCX3HjNpZ/jxeLZb4tm/kHiZ77mziCxZzy0cd8wTRJCiqDsSRqOR0gyC8+j3ffnZpLMGvMWRPfZ/87uBFagisZuqfzAb7P3+QVYiFknMxMjYpGImbB2t2HH1kadsmRrWXFGrkqX5TLxP6cqy2soa6trO4GdCmCmXToDmCtuKXj/ZyBcBEwQ3fvOvtv7qRSwgAQ4mq6lFACOaaw0uy1ldv9zuuKQSO46+Dl0Do9Oylz/M5dCGNyOU6+ueMEx1eTggIMuIVsO8utrIbVMv07ZhkxjhvHZUs
 [...]
+  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, 
U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, 
U+0329, U+1EA0-1EF9, U+20AB;
+}
+/* latin-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAC5gABIAAAAAcywAAC36AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGkAbjgwcgTAGYACDFAhUCYM8EQwKgbckgaVCC4N6ABKCCAE2AiQDh3AEIAWCdAcgDIJJGxxnJWybRvHgPADRiPpto6hJe1QiimDjIEDErxz8/+fkZAyBOmNq3n64RJGVYTsuMvUITcoKDzKbnypbeOMbTMui6C1taW9RKNHcVufFfHmORoTFgPXPgSnw9b5+VMOftv6L4lsP7Nfim5v2Fg/56vZtj9Xi2X1oL6wcCiUVkSRoowcKbqtiCxv72hEa+ySXh8iOvlc9XT27H+cQIKJzkEqRldoRFJE77dfP5dv9SY4YVAl4fHV0YXyVAjauylb1hue32fuUFViBOF1ahVEzCqsHioGKGBg5nZvTKYoJ6sSq6UQbF4o9l+mqzt3O2voMgP//fv
 [...]
+  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, 
U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAD2AABIAAAAAjnQAAD0aAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbmWQchV4GYACDIAhUCYM8EQwKgdx8gcR7C4QKABKCEAE2AiQDiBAEIAWCdAcgDIJJGzN/JezYiwK6AzihqSaqkQj7NFrlfHQg9jiQuO4X/P/nBM1EBrn5JK11TkWFUIRFnUFrFNvrPcp4DjlYevVgA0nxppzrUq2UwfojRitCYK27fdpSUHxF/dDCWlx/V1u8Guv6n+CPBeCi/9HtCEOUiBJRQoED6JkYbb+j7GNtuz+jRvSEZ/S00A7a2OhRipW6qzPAnRzRiJOHcO0f/0wy2b1bAsXMrrbsmBUhK0BVxx9efp7f5p/73qPEAETsPwy00f6KxdJqDIyKVRq5FmPZzFW5bKs2e9nKAG2zQ0Rdq2ivdNPVuxmRGFE4CwsLG8FAULHABE
 [...]
+  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, 
U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, 
U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+</style><g id="shape-7abbe548-0101-8074-8003-bc3c29bacfd3"><defs><clipPath 
class="frame-clip-def frame-clip" 
id="frame-clip-7abbe548-0101-8074-8003-bc3c29bacfd3-rumext-id-73"><rect rx="0" 
ry="0" x="0" y="0" width="480" height="360" transform="matrix(1.000000, 
0.000000, 0.000000, 1.000000, 0.000000, 0.000000)"/></clipPath></defs><g 
clip-path="url(#frame-clip-7abbe548-0101-8074-8003-bc3c29bacfd3-rumext-id-73)" 
fill="none"><clipPath class="frame-clip-def frame-clip" 
id="frame-clip-7abbe548- [...]
\ No newline at end of file
diff --git a/contrib/svg/maintenance.svg b/contrib/svg/maintenance.svg
new file mode 100644
index 0000000..c9899d1
--- /dev/null
+++ b/contrib/svg/maintenance.svg
@@ -0,0 +1,71 @@
+<svg xmlns:xlink="http://www.w3.org/1999/xlink"; width="480" 
xmlns="http://www.w3.org/2000/svg"; height="360" 
id="screenshot-2d5b5ebd-d89e-8002-8003-bc38a7b7f398" viewBox="0 0 480 360" 
style="-webkit-print-color-adjust: exact;" fill="none" version="1.1"><style 
data-loading="false">@font-face {
+    font-family: 'sourcesanspro';
+    font-style: normal;
+    font-weight: 400;
+    font-display: block;
+    src: 
url(data:font/woff;base64,d09GRgABAAAAAHSMABQAAAABDCAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQVNFAAABvAAAAD4AAABQinOTf0ZGVE0AAAH8AAAAHAAAABxwkYDFR0RFRgAAAhgAAAAiAAAAJgAnARBHUE9TAAACPAAACzwAADXwmf/bv0dTVUIAAA14AAAA+gAAAa7khdupT1MvMgAADnQAAABXAAAAYGdamnRjbWFwAAAOzAAAAYkAAAHiSESmoGN2dCAAABBYAAAAVgAAAFYUww7lZnBnbQAAELAAAAGxAAACZVO0L6dnYXNwAAASZAAAAAgAAAAIAAAAEGdseWYAABJsAABQOgAAm1B0O5TbaGVhZAAAYqgAAAAxAAAANgkVq9doaGVhAABi3AAAAB8AAAAkDmAFi2htdHgAAGL8AAACOgAAA6h47lnNbG9jYQAAZTgAAAHIAAAB1smHp
 [...]
+  }
+/* cyrillic-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAADvwABIAAAAAjVwAADuKAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoFOG5JCHDYGYACCWAhUCYM8EQwKgegwgdA5C4NaABKBeAE2AiQDhzAEIAWCdAcgDIJJG1F+FdwYN3AeQFB+677abITtcRB8qCaK0k06uOD/rwlqyNg/1gG4OUtEGEGmirCEmqCnVGr8zsRmprTwyRyCfbliCOmQx9q6Mj5be/suy4CgRfxSwkp8rM+rmfWO0aAxlI/2bxhtsYiy9ZR3ZZiGPUfJ5eLCH0Og40B+5lS4+JZbREd3WtkRGvskl+f/s3v+f1b32tUPREaEUgQoBBjJsfAljRyMLk4N8XP7extjgFQJkkYTgjWLlAqleiNzwEBCpAY4YhuwTVIYgoyRGyKbgIgB0iHoB8XA+OZ8Ou2bGY00gAJL9liSUY6TeDNLnPx/QJA9Ln
 [...]
+  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, 
U+FE2E-FE2F;
+}
+/* cyrillic */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAACWcABIAAAAAWLAAACU5AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmobllYcNgZgAIIECFQJgzwRDAqBgWzzRAuCEAASgRQBNgIkA4QcBCAFgnQHIAyCSRtATxVsXGWGjQMMs+lnUBRVo81EUaPVpDXB/1+TmzJwD1T/qiCyZNisrEoqJdLUU4XdGFQhjzBlqe+erlaQaExxJzlQcKB465SpoPV52dI8GZeWGJIUaZVuemk76uNVowWj6Dl7XlNSpinpy1R//+CHMHBkVqDYZD5CSx/xEkR2/Fe927Mz/wxHZgogFOLL3jllJCU50T//nvXnJqmmwkDFJoWYDqR2oHRFf+0+Gd/y12qA5tatRDKsgSA2VhxVNl2DFql2TqkeY8jIjTIP+o4HxoNBSIVEjciRBq+PVWu2e4RzCU8YpmLECyEJFPCpR2O2y4d/ni
 [...]
+  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
+}
+/* greek-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAAXMABIAAAAACeAAAAVwAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANAhUCYM8EQwKg2iDSgsQABIUATYCJAMcBCAFgnQHIAyCSRt8CAieB2WbnmbLuYAwwpK8+iIe4P3r89wHDZaakNWCmB8R66SEWr+ILhpijnTqf6QAyyF8GVAOAPOWtmNg6llFXANTaQXCgXMubThOj6JRPCJsEWW3o1/4wX411uruvta/9FF8Zz50qenu3hVxmf4QIi1dRSzhkcR0SqA1QoiwzI2uAUbffgtBpA0YCssEQRChiaaAgMpAFvDsmKQshIEEer1l/u1J0Sbi8P6OJsQc3VHd6N0nlHe1MAhFbvPNcXJVWKNNekPqCYVx/lj8nqMi5BY4Pd6hectSY5E2Lll8SMf/HJXfEKEOfCtEMjEFBEHtpSkbjBK4aB1MIE
 [...]
+  unicode-range: U+1F00-1FFF;
+}
+/* greek */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABvIABIAAAAAOYgAABtmAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbjEocNgZgAIFkCFQJgzwRDArPdMcZC4FIABJwATYCJAODDAQgBYJ0ByAMgkkbLzMV3Bg3cB5AgtL+dFGUC8ojwf9fE9SQsQftHoablcBAJCnZiWWrVQuV5mlVJ2ZKaJa1O4xgpZOeStdtJqxoMWTv3rvjdJiEUBrhQCzjWKrrzr+v3IEvgtjCHD1r8RMqj2DUbHUyl4hbe5lIDkAEEv7BTsC+xxGuHLLDJzwiHqGlj3jhedKj/3NHyYLOPksVyBbSB1V0wvzv2n/ewGQCNDPJ4CNcyi6XXCtkT9WCK7lfZQjUdwVhSH0hX5Qr6naI5na/NTmQyDBHdEm3iAEoMEJG1gSjB2IwqiywRvWIHoLRPK+/h3l+b/sICQgQDouxxGMEJJh57K
 [...]
+  unicode-range: U+0370-03FF;
+}
+/* vietnamese */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABW4ABIAAAAANeQAABVYAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGjQbhlocNgZgAIEACFQJgzwRDArNRMZyC4IWABKBFAE2AiQDhCgEIAWCdAcgDIJJG0QwsxE2bBxAgN2rQPJ/ODCHzPnAWwWN2o42Fh2ljaWNtCCX3HjNpZ/jxeLZb4tm/kHiZ77mziCxZzy0cd8wTRJCiqDsSRqOR0gyC8+j3ffnZpLMGvMWRPfZ/87uBFagisZuqfzAb7P3+QVYiFknMxMjYpGImbB2t2HH1kadsmRrWXFGrkqX5TLxP6cqy2soa6trO4GdCmCmXToDmCtuKXj/ZyBcBEwQ3fvOvtv7qRSwgAQ4mq6lFACOaaw0uy1ldv9zuuKQSO46+Dl0Do9Oylz/M5dCGNyOU6+ueMEx1eTggIMuIVsO8utrIbVMv07ZhkxjhvHZUs
 [...]
+  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, 
U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, 
U+0329, U+1EA0-1EF9, U+20AB;
+}
+/* latin-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAC5gABIAAAAAcywAAC36AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGkAbjgwcgTAGYACDFAhUCYM8EQwKgbckgaVCC4N6ABKCCAE2AiQDh3AEIAWCdAcgDIJJGxxnJWybRvHgPADRiPpto6hJe1QiimDjIEDErxz8/+fkZAyBOmNq3n64RJGVYTsuMvUITcoKDzKbnypbeOMbTMui6C1taW9RKNHcVufFfHmORoTFgPXPgSnw9b5+VMOftv6L4lsP7Nfim5v2Fg/56vZtj9Xi2X1oL6wcCiUVkSRoowcKbqtiCxv72hEa+ySXh8iOvlc9XT27H+cQIKJzkEqRldoRFJE77dfP5dv9SY4YVAl4fHV0YXyVAjauylb1hue32fuUFViBOF1ahVEzCqsHioGKGBg5nZvTKYoJ6sSq6UQbF4o9l+mqzt3O2voMgP//fv
 [...]
+  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, 
U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAD2AABIAAAAAjnQAAD0aAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbmWQchV4GYACDIAhUCYM8EQwKgdx8gcR7C4QKABKCEAE2AiQDiBAEIAWCdAcgDIJJGzN/JezYiwK6AzihqSaqkQj7NFrlfHQg9jiQuO4X/P/nBM1EBrn5JK11TkWFUIRFnUFrFNvrPcp4DjlYevVgA0nxppzrUq2UwfojRitCYK27fdpSUHxF/dDCWlx/V1u8Guv6n+CPBeCi/9HtCEOUiBJRQoED6JkYbb+j7GNtuz+jRvSEZ/S00A7a2OhRipW6qzPAnRzRiJOHcO0f/0wy2b1bAsXMrrbsmBUhK0BVxx9efp7f5p/73qPEAETsPwy00f6KxdJqDIyKVRq5FmPZzFW5bKs2e9nKAG2zQ0Rdq2ivdNPVuxmRGFE4CwsLG8FAULHABE
 [...]
+  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, 
U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, 
U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+</style><g id="shape-2d5b5ebd-d89e-8002-8003-bc38a7b7f398"><defs><clipPath 
class="frame-clip-def frame-clip" 
id="frame-clip-2d5b5ebd-d89e-8002-8003-bc38a7b7f398-rumext-id-29"><rect rx="0" 
ry="0" x="0" y="0" width="480" height="360" transform="matrix(1.000000, 
0.000000, 0.000000, 1.000000, 0.000000, 0.000000)"/></clipPath></defs><g 
clip-path="url(#frame-clip-2d5b5ebd-d89e-8002-8003-bc38a7b7f398-rumext-id-29)" 
fill="none"><clipPath class="frame-clip-def frame-clip" 
id="frame-clip-2d5b5ebd- [...]
\ No newline at end of file
diff --git a/contrib/svg/no-ip.svg b/contrib/svg/no-ip.svg
new file mode 100644
index 0000000..dd87818
--- /dev/null
+++ b/contrib/svg/no-ip.svg
@@ -0,0 +1,71 @@
+<svg xmlns:xlink="http://www.w3.org/1999/xlink"; width="480" 
xmlns="http://www.w3.org/2000/svg"; height="360" 
id="screenshot-2d5b5ebd-d89e-8002-8003-bc3b4c5926e8" viewBox="0 0 480 360" 
style="-webkit-print-color-adjust: exact;" fill="none" version="1.1"><style 
data-loading="false">@font-face {
+    font-family: 'sourcesanspro';
+    font-style: normal;
+    font-weight: 400;
+    font-display: block;
+    src: 
url(data:font/woff;base64,d09GRgABAAAAAHSMABQAAAABDCAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQVNFAAABvAAAAD4AAABQinOTf0ZGVE0AAAH8AAAAHAAAABxwkYDFR0RFRgAAAhgAAAAiAAAAJgAnARBHUE9TAAACPAAACzwAADXwmf/bv0dTVUIAAA14AAAA+gAAAa7khdupT1MvMgAADnQAAABXAAAAYGdamnRjbWFwAAAOzAAAAYkAAAHiSESmoGN2dCAAABBYAAAAVgAAAFYUww7lZnBnbQAAELAAAAGxAAACZVO0L6dnYXNwAAASZAAAAAgAAAAIAAAAEGdseWYAABJsAABQOgAAm1B0O5TbaGVhZAAAYqgAAAAxAAAANgkVq9doaGVhAABi3AAAAB8AAAAkDmAFi2htdHgAAGL8AAACOgAAA6h47lnNbG9jYQAAZTgAAAHIAAAB1smHp
 [...]
+  }
+/* cyrillic-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAADvwABIAAAAAjVwAADuKAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoFOG5JCHDYGYACCWAhUCYM8EQwKgegwgdA5C4NaABKBeAE2AiQDhzAEIAWCdAcgDIJJG1F+FdwYN3AeQFB+677abITtcRB8qCaK0k06uOD/rwlqyNg/1gG4OUtEGEGmirCEmqCnVGr8zsRmprTwyRyCfbliCOmQx9q6Mj5be/suy4CgRfxSwkp8rM+rmfWO0aAxlI/2bxhtsYiy9ZR3ZZiGPUfJ5eLCH0Og40B+5lS4+JZbREd3WtkRGvskl+f/s3v+f1b32tUPREaEUgQoBBjJsfAljRyMLk4N8XP7extjgFQJkkYTgjWLlAqleiNzwEBCpAY4YhuwTVIYgoyRGyKbgIgB0iHoB8XA+OZ8Ou2bGY00gAJL9liSUY6TeDNLnPx/QJA9Ln
 [...]
+  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, 
U+FE2E-FE2F;
+}
+/* cyrillic */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAACWcABIAAAAAWLAAACU5AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmobllYcNgZgAIIECFQJgzwRDAqBgWzzRAuCEAASgRQBNgIkA4QcBCAFgnQHIAyCSRtATxVsXGWGjQMMs+lnUBRVo81EUaPVpDXB/1+TmzJwD1T/qiCyZNisrEoqJdLUU4XdGFQhjzBlqe+erlaQaExxJzlQcKB465SpoPV52dI8GZeWGJIUaZVuemk76uNVowWj6Dl7XlNSpinpy1R//+CHMHBkVqDYZD5CSx/xEkR2/Fe927Mz/wxHZgogFOLL3jllJCU50T//nvXnJqmmwkDFJoWYDqR2oHRFf+0+Gd/y12qA5tatRDKsgSA2VhxVNl2DFql2TqkeY8jIjTIP+o4HxoNBSIVEjciRBq+PVWu2e4RzCU8YpmLECyEJFPCpR2O2y4d/ni
 [...]
+  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
+}
+/* greek-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAAXMABIAAAAACeAAAAVwAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbIBw2BmAANAhUCYM8EQwKg2iDSgsQABIUATYCJAMcBCAFgnQHIAyCSRt8CAieB2WbnmbLuYAwwpK8+iIe4P3r89wHDZaakNWCmB8R66SEWr+ILhpijnTqf6QAyyF8GVAOAPOWtmNg6llFXANTaQXCgXMubThOj6JRPCJsEWW3o1/4wX411uruvta/9FF8Zz50qenu3hVxmf4QIi1dRSzhkcR0SqA1QoiwzI2uAUbffgtBpA0YCssEQRChiaaAgMpAFvDsmKQshIEEer1l/u1J0Sbi8P6OJsQc3VHd6N0nlHe1MAhFbvPNcXJVWKNNekPqCYVx/lj8nqMi5BY4Pd6hectSY5E2Lll8SMf/HJXfEKEOfCtEMjEFBEHtpSkbjBK4aB1MIE
 [...]
+  unicode-range: U+1F00-1FFF;
+}
+/* greek */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABvIABIAAAAAOYgAABtmAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbjEocNgZgAIFkCFQJgzwRDArPdMcZC4FIABJwATYCJAODDAQgBYJ0ByAMgkkbLzMV3Bg3cB5AgtL+dFGUC8ojwf9fE9SQsQftHoablcBAJCnZiWWrVQuV5mlVJ2ZKaJa1O4xgpZOeStdtJqxoMWTv3rvjdJiEUBrhQCzjWKrrzr+v3IEvgtjCHD1r8RMqj2DUbHUyl4hbe5lIDkAEEv7BTsC+xxGuHLLDJzwiHqGlj3jhedKj/3NHyYLOPksVyBbSB1V0wvzv2n/ewGQCNDPJ4CNcyi6XXCtkT9WCK7lfZQjUdwVhSH0hX5Qr6naI5na/NTmQyDBHdEm3iAEoMEJG1gSjB2IwqiywRvWIHoLRPK+/h3l+b/sICQgQDouxxGMEJJh57K
 [...]
+  unicode-range: U+0370-03FF;
+}
+/* vietnamese */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAABW4ABIAAAAANeQAABVYAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGjQbhlocNgZgAIEACFQJgzwRDArNRMZyC4IWABKBFAE2AiQDhCgEIAWCdAcgDIJJG0QwsxE2bBxAgN2rQPJ/ODCHzPnAWwWN2o42Fh2ljaWNtCCX3HjNpZ/jxeLZb4tm/kHiZ77mziCxZzy0cd8wTRJCiqDsSRqOR0gyC8+j3ffnZpLMGvMWRPfZ/87uBFagisZuqfzAb7P3+QVYiFknMxMjYpGImbB2t2HH1kadsmRrWXFGrkqX5TLxP6cqy2soa6trO4GdCmCmXToDmCtuKXj/ZyBcBEwQ3fvOvtv7qRSwgAQ4mq6lFACOaaw0uy1ldv9zuuKQSO46+Dl0Do9Oylz/M5dCGNyOU6+ueMEx1eTggIMuIVsO8utrIbVMv07ZhkxjhvHZUs
 [...]
+  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, 
U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, 
U+0329, U+1EA0-1EF9, U+20AB;
+}
+/* latin-ext */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAC5gABIAAAAAcywAAC36AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGkAbjgwcgTAGYACDFAhUCYM8EQwKgbckgaVCC4N6ABKCCAE2AiQDh3AEIAWCdAcgDIJJGxxnJWybRvHgPADRiPpto6hJe1QiimDjIEDErxz8/+fkZAyBOmNq3n64RJGVYTsuMvUITcoKDzKbnypbeOMbTMui6C1taW9RKNHcVufFfHmORoTFgPXPgSnw9b5+VMOftv6L4lsP7Nfim5v2Fg/56vZtj9Xi2X1oL6wcCiUVkSRoowcKbqtiCxv72hEa+ySXh8iOvlc9XT27H+cQIKJzkEqRldoRFJE77dfP5dv9SY4YVAl4fHV0YXyVAjauylb1hue32fuUFViBOF1ahVEzCqsHioGKGBg5nZvTKYoJ6sSq6UQbF4o9l+mqzt3O2voMgP//fv
 [...]
+  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, 
U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: 
url(data:font/woff2;base64,d09GMgABAAAAAD2AABIAAAAAjnQAAD0aAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbmWQchV4GYACDIAhUCYM8EQwKgdx8gcR7C4QKABKCEAE2AiQDiBAEIAWCdAcgDIJJGzN/JezYiwK6AzihqSaqkQj7NFrlfHQg9jiQuO4X/P/nBM1EBrn5JK11TkWFUIRFnUFrFNvrPcp4DjlYevVgA0nxppzrUq2UwfojRitCYK27fdpSUHxF/dDCWlx/V1u8Guv6n+CPBeCi/9HtCEOUiBJRQoED6JkYbb+j7GNtuz+jRvSEZ/S00A7a2OhRipW6qzPAnRzRiJOHcO0f/0wy2b1bAsXMrrbsmBUhK0BVxx9efp7f5p/73qPEAETsPwy00f6KxdJqDIyKVRq5FmPZzFW5bKs2e9nKAG2zQ0Rdq2ivdNPVuxmRGFE4CwsLG8FAULHABE
 [...]
+  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, 
U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, 
U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+</style><g id="shape-2d5b5ebd-d89e-8002-8003-bc3b4c5926e8"><defs><clipPath 
class="frame-clip-def frame-clip" 
id="frame-clip-2d5b5ebd-d89e-8002-8003-bc3b4c5926e8-rumext-id-38"><rect rx="0" 
ry="0" x="0" y="0" width="479.9999999999999" height="360" 
transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 
0.000000)"/></clipPath></defs><g 
clip-path="url(#frame-clip-2d5b5ebd-d89e-8002-8003-bc3b4c5926e8-rumext-id-38)" 
fill="none"><clipPath class="frame-clip-def frame-clip" id="frame- [...]
\ No newline at end of file
diff --git a/contrib/taler-mdb-show.sh b/contrib/taler-mdb-show.sh
new file mode 100644
index 0000000..a050002
--- /dev/null
+++ b/contrib/taler-mdb-show.sh
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+set -eu
+
+function cleanup()
+{
+    taler-mdb-display-off -c "$CONF" -i
+    exit 0
+}
+
+trap cleanup EXIT
+
+CONF="$HOME/.config/taler.conf"
+
+# Parse command-line options
+while getopts ':c:h' OPTION; do
+    case "$OPTION" in
+        c)
+            CONF="$OPTARG"
+            ;;
+        h)
+            echo 'Supported options:'
+            # shellcheck disable=SC2016
+            echo '  -c $CONF     -- set configuration'
+            ;;
+        ?)
+            exit_fail "Unrecognized command line option"
+            ;;
+    esac
+done
+
+taler-mdb-display-on -c "$CONF"
+
+FBDEV=$(taler-config -c "$CONF" -s taler-mdb -o FRAMEBUFFER_DEVICE)
+
+fbi -d "$FBDEV" -a -m "768x576-75" -vt 2 -nocomments -noverbose "$1.png"
+
+while true
+do
+    sleep 10
+done
diff --git a/debian/taler-mdb.postrm.debhelper 
b/debian/taler-mdb.postrm.debhelper
index 5d2556c..0847f23 100644
--- a/debian/taler-mdb.postrm.debhelper
+++ b/debian/taler-mdb.postrm.debhelper
@@ -1,4 +1,4 @@
-# Automatically added by dh_installdebconf/13.3
+# Automatically added by dh_installdebconf/13.11.4ubuntu3
 if [ "$1" = purge ] && [ -e /usr/share/debconf/confmodule ]; then
        . /usr/share/debconf/confmodule
        db_purge
diff --git a/debian/taler-mdb.service b/debian/taler-mdb.service
index 4946e41..ec2c8cb 100644
--- a/debian/taler-mdb.service
+++ b/debian/taler-mdb.service
@@ -5,7 +5,7 @@ Description=GNU Taler Multi-Drop-Bus application
 User=root
 Type=simple
 Restart=on-failure
-ExecStart=/usr/bin/taler-mdb-network-check.sh -c /etc/taler-mdb.conf -f 
"FIXME-show-message-cmd" /usr/bin/taler-mdb -c /etc/taler-mdb.conf
+ExecStart=/usr/bin/taler-mdb-network-check.sh -c /etc/taler-mdb.conf -f 
'/usr/bin/taler-mdb-show.sh -c /etc/taler-mdb.conf' /usr/bin/taler-mdb -c 
/etc/taler-mdb.conf
 StandardOutput=inherit
 StandardError=inherit
 Restart=always
diff --git a/debian/taler-mdb.substvars b/debian/taler-mdb.substvars
index 0248013..1c0d4e3 100644
--- a/debian/taler-mdb.substvars
+++ b/debian/taler-mdb.substvars
@@ -1,3 +1,3 @@
 misc:Depends=debconf (>= 0.5) | debconf-2.0
-shlibs:Depends=libc6 (>= 2.14), libgnunet (>= 0.14.0), libjansson4 (>= 2.0.1), 
libnfc5 (>= 1.7.0~rc2), libqrencode4 (>= 3.2.0), libtalerexchange (>= 0.9.0), 
libtalermerchant (>= 0.9.0)
+shlibs:Depends=libc6 (>= 2.34), libgnunet (>= 0.20.0), libjansson4 (>= 2.14), 
libnfc6 (>= 1.7.0~rc2), libqrencode4 (>= 3.2.0), libtalerexchange (>= 0.9.3), 
libtalermerchant (>= 0.9.3)
 misc:Pre-Depends=
diff --git a/src/Makefile.am b/src/Makefile.am
index c48d4bb..42463c2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,7 +1,8 @@
 # This Makefile.am is in the public domain
 bin_PROGRAMS = \
   taler-coin-acceptor \
-  taler-mdb
+  taler-mdb \
+  taler-mdb-display
 
 if HAVE_QR
 bin_PROGRAMS += qr-show
@@ -43,3 +44,10 @@ qr_show_LDADD = \
   @QR_LIBS@ \
   $(XLIB)
 
+
+taler-mdb-display_SOURCES = \
+  taler-mdb-display.c
+taler-mdb-display_LDADD = \
+  -lgnunetutil \
+  $(XLIB)
+
diff --git a/src/taler-mdb-display.c b/src/taler-mdb-display.c
new file mode 100644
index 0000000..d486427
--- /dev/null
+++ b/src/taler-mdb-display.c
@@ -0,0 +1,312 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 Taler Systems SA
+
+ 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.
+
+ 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
+ TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+* @file taler-mdb-display-on.c
+* @brief turn on the display back light
+* @author Boss Marco
+* @author Christian Grothoff
+*/
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#if HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_NETINET_IP_H
+#include <netinet/ip.h>         /* superset of previous */
+#endif
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <termios.h>
+#include <microhttpd.h>
+#include <gnunet/gnunet_util_lib.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+/* for adafruit pitft display */
+#include <linux/fb.h>
+
+/**
+ * Disable i18n support.
+ */
+#define _(s) (s)
+
+/**
+ * Handle for the Framebuffer device
+ */
+struct Display
+{
+  /**
+   * File descriptor for the screen
+   */
+  int devicefd;
+
+  /**
+   * File descriptor to set backlight information
+   */
+  int backlightfd;
+
+  /**
+   * The display memory to set the pixel information
+   */
+  uint16_t *memory;
+
+  /**
+   * Original screen information
+   */
+  struct fb_var_screeninfo orig_vinfo;
+
+  /**
+   * Variable screen information (color depth ...)
+   */
+  struct fb_var_screeninfo var_info;
+
+  /**
+   * Fixed screen informtaion
+   */
+  struct fb_fix_screeninfo fix_info;
+};
+
+
+/**
+ * Next program to launch.
+ */
+static char *const *arg_next;
+
+/**
+ * Name of the framebuffer device (i.e. /dev/fb1).
+ */
+static char *framebuffer_device_filename;
+
+/**
+ * Name of the backlight file of @e framebuffer_device_filename (i.e. 
/sys/class/backlight/soc:backlight/brightness).
+ */
+static char *framebuffer_backlight_filename;
+
+/**
+ * Global option '-i' to invert backlight on/off values
+ */
+static int backlight_invert;
+
+/**
+ * Standard backlight on value
+ */
+static char backlight_on = '1';
+
+/**
+ * Standard backlight off value
+ */
+static char backlight_off = '0';
+
+/**
+ * Handle for the framebuffer device
+ */
+static struct Display qrDisplay;
+
+
+static void
+shutdown_task (void *cls)
+{
+  (void) cls;
+  if (NULL != qrDisplay.memory)
+    memset (qrDisplay.memory,
+            0xFF,
+            qrDisplay.var_info.xres * qrDisplay.var_info.yres
+            * sizeof (uint16_t));
+  if (NULL != qrDisplay.memory)
+  {
+    /* free the display data  */
+    munmap (qrDisplay.memory,
+            qrDisplay.fix_info.smem_len);
+    qrDisplay.memory = NULL;
+    /* close device */
+    GNUNET_break (0 == close (qrDisplay.devicefd));
+    qrDisplay.devicefd = -1;
+    if (0 < qrDisplay.backlightfd)
+      GNUNET_break (0 == close (qrDisplay.backlightfd));
+    qrDisplay.backlightfd = -1;
+  }
+}
+
+
+/**
+ * @brief Start the application
+ *
+ * @param cls closure
+ * @param args arguments left
+ * @param cfgfile config file name
+ * @param cfg handle for the configuration file
+ */
+static void
+run (void *cls,
+     char *const *args,
+     const char *cfgfile,
+     const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  (void) cls;
+  (void) cfgfile;
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (cfg,
+                                               "taler-mdb",
+                                               "FRAMEBUFFER_DEVICE",
+                                               &framebuffer_device_filename))
+  {
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               "taler-mdb",
+                               "FRAMEBUFFER_DEVICE");
+    framebuffer_device_filename = GNUNET_strdup ("/dev/fb1");
+  }
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (cfg,
+                                               "taler-mdb",
+                                               "FRAMEBUFFER_BACKLIGHT",
+                                               
&framebuffer_backlight_filename))
+  {
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               "taler-mdb",
+                               "FRAMEBUFFER_BACKLIGHT");
+    framebuffer_backlight_filename = GNUNET_strdup (
+      "/sys/class/backlight/soc:backlight/brightness");
+  }
+  /* open the framebuffer device */
+  qrDisplay.devicefd = open (framebuffer_device_filename,
+                             O_RDWR);
+  if (0 < qrDisplay.devicefd)
+  {
+    /* read information about the screen */
+    ioctl (qrDisplay.devicefd,
+           FBIOGET_VSCREENINFO,
+           &qrDisplay.var_info);
+
+    /* store current screeninfo for reset */
+    qrDisplay.orig_vinfo = qrDisplay.var_info;
+
+    if (16 != qrDisplay.var_info.bits_per_pixel)
+    {
+      /* Change variable info to 16 bit per pixel */
+      qrDisplay.var_info.bits_per_pixel = 16;
+      if (0 > ioctl (qrDisplay.devicefd,
+                     FBIOPUT_VSCREENINFO,
+                     &qrDisplay.var_info))
+      {
+        GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                             "ioctl(FBIOPUT_VSCREENINFO)");
+        return;
+      }
+    }
+
+    /* Get fixed screen information */
+    if (0 > ioctl (qrDisplay.devicefd,
+                   FBIOGET_FSCREENINFO,
+                   &qrDisplay.fix_info))
+    {
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                           "ioctl(FBIOGET_FSCREENINFO)");
+      return;
+    }
+
+    /* get pointer onto frame buffer */
+    qrDisplay.memory =  mmap (NULL,
+                              qrDisplay.fix_info.smem_len,
+                              PROT_READ | PROT_WRITE, MAP_SHARED,
+                              qrDisplay.devicefd,
+                              0);
+
+    /* open backlight file to turn display backlight on and off */
+    if (0 > qrDisplay.devicefd)
+    {
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                           "mmap");
+      return;
+    }
+
+    memset (qrDisplay.memory,
+            0xFF,
+            qrDisplay.var_info.xres * qrDisplay.var_info.yres
+            * sizeof (uint16_t));
+
+    qrDisplay.backlightfd = open (
+      framebuffer_backlight_filename, O_WRONLY);
+    if (0 > qrDisplay.backlightfd)
+    {
+      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+                                "open",
+                                framebuffer_backlight_filename);
+    }
+    else
+    {
+      if (backlight_invert)
+      {
+        backlight_on = '0';
+        backlight_off = '1';
+      }
+      (void) ! write (qrDisplay.backlightfd,
+                      &backlight_off,
+                      1);
+    }
+  }
+  else
+  {
+    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+                              "open",
+                              framebuffer_device_filename);
+  }
+  GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
+                                 NULL);
+
+  if (0 < qrDisplay.backlightfd)
+    (void) ! write (qrDisplay.backlightfd,
+                    &backlight_on,
+                    1);
+}
+
+
+int
+main (int argc,
+      char*const*argv)
+{
+  int ret;
+  /* the available command line options */
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_option_flag ('i',
+                               "backlight-invert",
+                               "invert the backlight on/off values (standard 
on = 1)",
+                               &backlight_invert),
+    GNUNET_GETOPT_OPTION_END
+  };
+
+  ret = GNUNET_PROGRAM_run (argc,
+                            argv,
+                            "taler-mdb-display-on",
+                            "Turn on display.\n",
+                            options,
+                            &run,
+                            NULL);
+  if (GNUNET_OK != ret)
+    return 1;
+  return 0;
+}

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]