initial commit

This commit is contained in:
error 2022-08-28 18:56:24 +02:00
commit 8091fdc5a7
14 changed files with 1795 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
__pycache__/
output/

24
README.md Normal file
View File

@ -0,0 +1,24 @@
# undefinedbehavior-website
Content for [undefinedbehavior.de](undefinedbehavior.de).
## Deployment
Clone the repository and generate the website using `pelican content -s publishconf.py`.
Refer to the [pelican documentation](https://docs.getpelican.com/en/latest/settings.html "Settings - Pelican") for details on how to configure pelican.
## Filters
In order to use sidenotes and lightboxes, add `filters.py` as custom jinja filters to your `pelicanconf.py`:
from sys import path
from os import curdir
path.append(curdir)
from filters import add_lightboxes, add_sidenotes
JINJA_FILTERS = {'add_lightboxes': add_lightboxes,
'add_sidenotes': add_sidenotes}
## License
Most content on this site is licensed unter the [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/ "Creative Commons - Attribution-NonCommercial 4.0 International") license.

159
content/favicon.svg Normal file
View File

@ -0,0 +1,159 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
sodipodi:docname="favicon.svg"
inkscape:version="1.2 (dc2aedaf03, 2022-05-15)"
sodipodi:version="0.32"
id="svg2"
height="100.00000pt"
width="100.00000pt"
version="1.1"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs3">
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend"
style="overflow:visible">
<path
sodipodi:nodetypes="cccc"
id="path2928"
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-0.6,0,0,-0.6,3,0)" />
</marker>
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Lend"
style="overflow:visible;">
<path
sodipodi:nodetypes="cccc"
id="path2931"
style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(1.1) rotate(180) translate(-5,0)" />
</marker>
<marker
inkscape:stockid="Arrow2Lstart"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Lstart"
style="overflow:visible">
<path
sodipodi:nodetypes="cccc"
id="path2922"
style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(1.1) translate(-5,0)" />
</marker>
</defs>
<sodipodi:namedview
inkscape:window-y="0"
inkscape:window-x="0"
inkscape:window-height="1019"
inkscape:window-width="1920"
inkscape:grid-points="true"
showgrid="true"
inkscape:current-layer="layer1"
inkscape:document-units="pt"
inkscape:cy="72.389693"
inkscape:cx="66.290084"
inkscape:zoom="4.3445412"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
inkscape:showpageshadow="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showguides="false"
inkscape:window-maximized="1">
<inkscape:grid
id="GridFromPre046Settings"
type="xygrid"
originx="0"
originy="0"
spacingx="6.6666667"
spacingy="6.6666667"
color="#3f3fff"
empcolor="#3f3fff"
opacity="0.15"
empopacity="0.38"
empspacing="5" />
</sodipodi:namedview>
<metadata
id="metadata4">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<cc:license
rdf:resource="http://creativecommons.org/publicdomain/zero/1.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/publicdomain/zero/1.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
</cc:License>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<ellipse
id="path1291"
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:4.37372;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
cx="72.325401"
cy="66.657509"
rx="58.419399"
ry="58.453125" />
<path
sodipodi:nodetypes="cc"
id="path2052"
d="M 42.608225,36.93892 V 96.373349"
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:3.9623;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="cc"
id="path2054"
d="M -16.826204,66.656135 H 42.608225"
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:3.9623;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccc"
id="path2056"
d="M 42.608225,56.750396 92.136916,17.127444 v -39.622951"
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:3.9623;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-mid:none" />
<path
sodipodi:nodetypes="ccc"
id="path2058"
d="M 42.608225,76.561873 67.372571,96.373349 92.136916,116.18483"
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:3.9623;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-mid:url(#Arrow2Mend)" />
<path
sodipodi:nodetypes="cc"
id="path9839"
d="M 92.136916,155.80778 V 116.18483"
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:3.9623;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.0 KiB

27
content/pages/contact.md Normal file
View File

@ -0,0 +1,27 @@
Title: Contact
Date: 2022-08-28 16:05
Author: Error
Status: published
Summary: Information on how to contact me
## Mail
My mail address is `error[at]mail.undefinedbehavior.de`. If you are using PGP, please encrypt your mails to me. You can find my PGP key here:
-----BEGIN PGP PUBLIC KEY BLOCK-----
mDMEYwtp4hYJKwYBBAHaRw8BAQdA1XZSdSIar5uXBMQeZz9/Yy76Prgm7eIUbTLC
+JphwPe0J0Vycm9yIDxlcnJvckBtYWlsLnVuZGVmaW5lZGJlaGF2aW9yLmRlPoiW
BBMWCAA+FiEEcndbgp2G18V3Liw84XAaKTGUmKcFAmMLaeICGwMFCQWjmoAFCwkI
BwIGFQoJCAsCBBYCAwECHgECF4AACgkQ4XAaKTGUmKeFLAEAtZQkfqD5WCi61Z6z
Nc5AbsFbtp3+i/SAcrBDTSSz8HwA/i/WYcAF/aiBQhOGmmChXVasBN6gwkH06zsj
wZOsa9kGuDgEYwtp4hIKKwYBBAGXVQEFAQEHQBiFyE8NTV/11+OYqmLoLAQhyOnN
3rP8hz/Ge0MBPLgPAwEIB4h+BBgWCAAmFiEEcndbgp2G18V3Liw84XAaKTGUmKcF
AmMLaeICGwwFCQWjmoAACgkQ4XAaKTGUmKcrZwD7Bg7BI/xHF+GsOZaLq9+6vExb
gynNULdp+6RzjtQqeBoA/A113EFA2XBPATWJfZmmUGHAxWvhcGqLIDACwbnWaPEJ
=+u+A
-----END PGP PUBLIC KEY BLOCK-----
## Mastodon
You can find me on chaos.social as <a rel="me" href="https://chaos.social/@Error">@Error</a>.

17
content/pages/credits.md Normal file
View File

@ -0,0 +1,17 @@
Title: Credits
Date: 2022-08-28 16:05
Author: Error
Status: hidden
Summary: Credit where credit is due
## Pelican
This site is powered by [Pelican](https://getpelican.com "Pelican Static Site Generator, Powered by Python"). Pelican is a static site generator written in python.
It's licensed under the [GNU Affero General Public License v3.0](https://www.gnu.org/licenses/#AGPL "GNU Affero General Public License")
## <span class="latex">L<span>A</span>T<span>E</span>X</span>.css
This site's template is based on [<span class="latex">L<span>A</span>T<span>E</span>X</span>.css](https://latex.now.sh "LaTeX.css"), a CSS library that makes a website look like a LaTeX document.
<span class="latex">L<span>A</span>T<span>E</span>X</span>.css is licensed under the MIT License.
The template can be found [here](https://git.undefinedbehavior.de/undef/undefined-pelican-theme "Undefined Pelican Theme").

16
content/pages/imprint.md Normal file
View File

@ -0,0 +1,16 @@
Title: Imprint
Date: 2022-08-28 16:05
Author: Error
Status: hidden
Summary: Legaly required contact information
## Disclaimer
This information is only provided for legal reasons. Please reach out to me via [e-mail or Mastodon](/pages/contact "Contact") instead. It's much faster and simpler.
## Verantwortlich gemäß §5 TMG
Felix Hallaczek
Heilmannstraße 4b
70190 Stuttgart
Germany

15
content/pages/privacy.md Normal file
View File

@ -0,0 +1,15 @@
Title: Privacy
Date: 2022-08-28 16:05
Author: Error
Status: hidden
Summary: Only necessary data is processed. No logging, no tracking, no analytics;
## Privacy Statement
This website only processes data that is necessary in order to fulfill the user's request, e.g. the user's IP address.
It does not generate access logs.
Personal data is discarded once the request was served.
This server only serves requests via HTTPS. All communication is end-to-end encrypted with TLS. Requests received on port 80 (HTTP) are redirected to port 443 (HTTPS).
If you're interested in more information on how this webside is delivered to your device, have a look at [RFC 9112](https://datatracker.ietf.org/doc/html/rfc9112 "HTTP/1.1") for HTTP/1.1 and [RFC 8446](https://datatracker.ietf.org/doc/html/rfc8446 "The Transport Layer Security (TLS) Protocol Version 1.3") for TLS 1.3.

87
content/posts/scroip.md Normal file
View File

@ -0,0 +1,87 @@
Title: Slot Car Racing over IP (SCRoIP)
Date: 2022-08-28 16:05
Author: Error
Slug: scroip
Summary: I built a remote control for a slot car racing track to play with it over the LAN. It's unnecessary complicated and inefficient, but at least it supports IPv6. Ladies, Gentlemen and everyone else, start your engines.
License: CC-BY-NC
https://creativecommons.org/licenses/by-nc/4.0/
## The Idea
When I was a child, I used to play a lot with my slot car racing track.
After stubling upon it again recently, I started wondering if I could build something to control it over the network.
Not that I needed a remote control for it, but it seemed like a fun project.
However, simply creating an API that offers precise control over the device seemed way to sriaght forward - the controling mechanism itself should add its challenges.
So I came up with the idea to control it with the traffic itself.
The more traffic is sent to the remote control, the faster the car is supposed to go.[°Use more bandwidth!!!]
## Reversing
In order to build the remote control, the first step was to figure out how the slot car racing system works. So I disassembled it and took a look at its wiring.
![Simplified circuit diagram for a slot car racing system]({static}/posts/scroip/carrera.svg "Simplified circuit diagram of a slot car racing system")
The underlying mechanism is fairly simple. The power supply provides about 14.8&nbsp;V DC voltage, which a used to power the car's motor.
The speed of the car is controlled by a variable resistor within the controller, which allows to control the voltage the car receives.
Pushing the controller further down lowers the resistance, which raises the voltage available to the car and makes is go faster.
A third wire is used to brake the car when the controller is in its neutral position by utilizing the current generated by the motor when the car is rolling out.
A look at wikipedia confirms this analysis. [^1]
## Building a digital Controller
Now that I understood the mechanism, the next step was to create a digital version of it, so that I could control the slot car racing track with a Raspberry Pi.
My first idea was to simply use a digital potentiometer.
However, searching for a suitable digipot, I quickly realized that there were no options with the desired dimensions of about 30&nbsp;&#8486; available.
Therefore I built it myself using a few resistors, solid state relais and multiplexers.[°I'm sure there are simpler solutions for this, but, well, it worked for me.]
![SCRoIP controller circuit diagram]({static}/posts/scroip/scroip.svg "SCRoIP controller circuit diagram")
For the sake of simplicity,[°or maybe out of laziness, who knows? :)] I did not add the braking mechanism from the analog controller to my digital version.
## Implementing the Server
With the hardware fully assembled and soldered, it was time to have a look at the software.
Python offers an easy way of implementing TCP servers.[°This project will use TCP. Even though the payload is immediately discarded, reliability is of the utmost importance and packet loss will not be accepted!!!]
By default, it only supports IPv4, but IPv6 support can be added by setting `address_family` to `AF_INET6`.
if not legacy:
self.address_family = AF_INET6
super(SCRoIPServer, self).__init__((address, port), SCRoIPRequestHandler)
The server's logic itself is implemented in the method `handle()` of the class `SCRoIPRequestHandler`. While there is an active connection, it reads from the socket and sums up the ammount of data that was received.
Once every 100 ms, it then calculates the average throughput for that time period and sets the raspi's GPIO pins accordingly.
while self.data != b'':
try:
self.data = self.request.recv(4096)
self.traffic_counter += len(self.data)
except TimeoutError:
pass
time = clock_gettime_ns(CLOCK_REALTIME)
diff = time - self.last
if (diff > 100000000):
self.last = time
traffic: float = self.traffic_counter / diff * 1000000000
print(f"{traffic} Bytes/s")
self.server.set_throttle(traffic)
self.server.apply_throttle()
self.traffic_counter = 0
The full server code can be found [here](https://git.undefinedbehavior.de/undef/SCRoIP "Slot Car Racing over IP - SCRoIP - undefined git server").
## Lights out and away we go
Once the server was implemented as well, all that was left to do was to test it.
So I deployed the server script to a Raspberry Pi, connected its GPIO pins to the controller and the controller to the slot car racing track.
Using netcat, I was now able to accelerate the car with the network traffic I generated:
<video controls preload="metadata">
<source src="{static}/posts/scroip/demo.webm" type="video/webm">
<p>
The video could not be loaded.
You can try to download it directly <a href="/posts/scroip/demo.webm">here</a> instead.
</p>
</video>
[^1]: [https://de.wikipedia.org/wiki/Autorennbahn#Fahrzeugsteuerung](https://de.wikipedia.org/wiki/Autorennbahn#Fahrzeugsteuerung "Autorennbahn Wikipedia")

View File

@ -0,0 +1,64 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- This file was generated by dvisvgm 2.13.3 -->
<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='1151.558811pt' height='616.470693pt' viewBox='-210.027861 -216.00015 1151.558811 616.470693'>
<defs>
<clipPath id='clip1'>
<path d='M223.2184 49.9492V26.1367H191.4684V49.9492ZM207.3434 49.9492C213.9184 49.9492 219.2504 44.6172 219.2504 38.043C219.2504 31.4648 213.9184 26.1367 207.3434 26.1367C200.7694 26.1367 195.4374 31.4648 195.4374 38.043C195.4374 44.6172 200.7694 49.9492 207.3434 49.9492ZM207.3434 38.043' clip-rule='evenodd'/>
</clipPath>
</defs>
<style type='text/css'>
<![CDATA[@font-face{font-family:cmsy10;src:url(data:application/x-font-woff;base64,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) format('woff');}
@font-face{font-family:cmmi10;src:url(data:application/x-font-woff;base64,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) format('woff');}
@font-face{font-family:cmr10;src:url(data:application/x-font-woff;base64,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) format('woff');}
text.f0 {font-family:cmsy10;font-size:9.96264px}
text.f1 {font-family:cmmi10;font-size:9.96264px}
text.f2 {font-family:cmr10;font-size:9.96264px}
]]>
</style>
<g id='page1' transform='matrix(3 0 0 3 0 0)'>
<path d='M101.043 45.1289V-11.5664C101.043-25.7383 143.5625-4.4805 143.5625 9.6953V16.7813M108.1289 45.1289V9.6953C108.1289 2.6094 108.1289 2.6094 122.3047 9.6953C136.4766 16.7813 136.4766 16.7813 136.4766 23.8672V45.1289C136.4766 52.2148 136.4766 52.2148 129.3906 52.2148H115.2148C108.1289 52.2148 108.1289 52.2148 108.1289 45.1289M129.3906 40.875C129.3906 36.9609 126.2187 33.7891 122.3047 33.7891C118.3906 33.7891 115.2148 36.9609 115.2148 40.875S118.3906 47.9648 122.3047 47.9648C126.2187 47.9648 129.3906 44.7891 129.3906 40.875ZM123.7187 28.1211C123.7187 25.7734 121.8164 23.8672 119.4687 23.8672C117.1211 23.8672 115.2148 25.7734 115.2148 28.1211S117.1211 32.3711 119.4687 32.3711C121.8164 32.3711 123.7187 30.4688 123.7187 28.1211ZM120.8867 18.1992C120.8867 16.6328 119.6172 15.3633 118.0508 15.3633S115.2148 16.6328 115.2148 18.1992S116.4844 21.0352 118.0508 21.0352S120.8867 19.7656 120.8867 18.1992ZM101.043 45.1289C101.043 59.3008 101.043 59.3008 115.2148 59.3008H299.4724C313.6444 59.3008 313.6444 59.3008 313.6444 45.1289V-11.5664C313.6444-25.7383 271.1254-4.4805 271.1254 9.6953V16.7813M306.5584 45.1289V9.6953C306.5584 2.6094 306.5584 2.6094 292.3824 9.6953C278.2114 16.7813 278.2114 16.7813 278.2114 23.8672V45.1289C278.2114 52.2148 278.2114 52.2148 285.2964 52.2148H299.4724C306.5584 52.2148 306.5584 52.2148 306.5584 45.1289M299.4724 40.875C299.4724 36.9609 296.2964 33.7891 292.3824 33.7891S285.2964 36.9609 285.2964 40.875S288.4684 47.9648 292.3824 47.9648S299.4724 44.7891 299.4724 40.875ZM299.4724 28.1211C299.4724 25.7734 297.5664 23.8672 295.2184 23.8672C292.8714 23.8672 290.9684 25.7734 290.9684 28.1211S292.8714 32.3711 295.2184 32.3711C297.5664 32.3711 299.4724 30.4688 299.4724 28.1211ZM299.4724 18.1992C299.4724 16.6328 298.2034 15.3633 296.6364 15.3633C295.0704 15.3633 293.8004 16.6328 293.8004 18.1992S295.0704 21.0352 296.6364 21.0352C298.2034 21.0352 299.4724 19.7656 299.4724 18.1992ZM171.9102 16.7813L178.9964 23.8672C181.8324 26.7031 181.8324 26.7031 184.6684 26.7031H230.0194C232.8554 26.7031 232.8554 26.7031 235.6914 23.8672L242.7774 16.7813M149.2344 59.3008L152.0664 56.4688C154.9023 53.6328 154.9023 53.6328 157.7383 53.6328H256.9494C259.7854 53.6328 259.7854 53.6328 262.6214 56.4688L265.4534 59.3008M140.7305 2.6094C169.0742 8.2773 245.6134 8.2773 273.9574 2.6094M133.6406-4.4805L142.1445-18.6523C159.1523-46.9998 255.5354-46.9998 272.5434-18.6523L281.0464-4.4805M272.5434-18.6523C264.0394-35.6598 150.6484-35.6598 142.1445-18.6523M122.3047-11.5664V-32.8238H123.7227V-10.7148M123.7227-30.5588H156.7461M123.7227-19.2187H142.4297M292.3824-11.5664V-32.8238H290.9644V-10.7148M290.9644-30.5588H257.9414M290.9644-19.2187H272.2574M108.1289 59.3008V64.97266H136.4766V59.3008M306.5584 59.3008V64.97266H278.2114V59.3008' stroke='#bfbfbf' fill='none' stroke-width='.3985'/>
<path d='M-12.1836-48.8128L15.8398-55.8168C19.8437-56.8168 20.7227-55.2618 17.8047-52.3438C1.8281-36.3668 1.8281-36.3668 11.4023-26.7968C11.9883-26.2109 12.0898-25.1836 11.6289-24.4961C3.957-12.9844 3.957-12.9844 11.4023-5.5352C11.9883-4.9531 12.0898-3.9219 11.6289-3.2344C3.957 8.2773 3.957 8.2773 11.4023 15.7266C11.9883 16.3086 12.0898 17.3398 11.6289 18.0234C3.957 29.5391 3.957 29.5391 19.0508 53.0156C21.2812 56.4883 19.7461 59.3008 15.6172 59.3008H-11.957C-16.0859 59.3008-20.3672 56.0898-21.5234 52.1289C-34.3126 8.2773-34.3126 8.2773-29.1016-24.7344C-28.4566-28.8128-26.2734-35.0198-24.2266-38.6058L-23.1367-40.5118C-21.0898-44.0938-16.1836-47.8088-12.1836-48.8128ZM-5.2578-50.5428V-67.5508L-13.7617-65.4258V-66.8438L6.082-71.8008V-70.3868L-2.4219-68.2578V-51.2498' stroke='#bfbfbf' fill='none' stroke-width='.3985' stroke-miterlimit='10'/>
<path d='M-40.6916 106.0234V125.9648M-12.3438-28.5738M-12.3438 30.9531V101.8203H-22.5508M-40.6916 101.8203H-30.4846M-40.6916 130.168H-33.6056M-33.6056 130.168H-26.5156V105.7891M-26.5156 97.8555V-34.2418H-19.4297M-19.4297-34.2418H-12.3438M3.5312 1.1914V101.8203H171.9102V52.2148V46.8281M171.9102 15.082V9.6953H203.3754M211.3124 9.6953H242.7774V15.082M242.7774 46.8281V52.2148V130.168H-26.5156M186.0824 9.6953V23.8672M186.0824 23.8672V38.043M186.0824 38.043H223.2184M191.4684 38.043H228.6054M228.6054 38.043V23.8672M228.6054 23.8672V9.6953' stroke='#000' fill='none' stroke-width='.3985' stroke-miterlimit='10'/>
<text class='f2' x='72.696413' y='73.475155' transform='matrix(1 0 0 1 -124.6559 30.8378)'>+</text>
<path d='M-39.1056 101.8203C-39.1056 100.9453-39.8126 100.2344-40.6916 100.2344C-41.5666 100.2344-42.2776 100.9453-42.2776 101.8203C-42.2776 102.6992-41.5666 103.4102-40.6916 103.4102C-39.8126 103.4102-39.1056 102.6992-39.1056 101.8203Z' fill='#fff'/>
<path d='M-39.1056 101.8203C-39.1056 100.9453-39.8126 100.2344-40.6916 100.2344C-41.5666 100.2344-42.2776 100.9453-42.2776 101.8203C-42.2776 102.6992-41.5666 103.4102-40.6916 103.4102C-39.8126 103.4102-39.1056 102.6992-39.1056 101.8203Z' stroke='#000' fill='none' stroke-width='.3985' stroke-miterlimit='10'/>
<path d='M-39.1056 130.168C-39.1056 129.293-39.8126 128.582-40.6916 128.582C-41.5666 128.582-42.2776 129.293-42.2776 130.168C-42.2776 131.0469-41.5666 131.7578-40.6916 131.7578C-39.8126 131.7578-39.1056 131.0469-39.1056 130.168Z' fill='#fff'/>
<path d='M-39.1056 130.168C-39.1056 129.293-39.8126 128.582-40.6916 128.582C-41.5666 128.582-42.2776 129.293-42.2776 130.168C-42.2776 131.0469-41.5666 131.7578-40.6916 131.7578C-39.8126 131.7578-39.1056 131.0469-39.1056 130.168Z' stroke='#000' fill='none' stroke-width='.3985' stroke-miterlimit='10'/>
<path d='M-40.6916 121.75H-42.6756L-40.6916 125.9648L-38.7066 121.75Z'/>
<path d='M-40.6916 121.75H-42.6756L-40.6916 125.9648L-38.7066 121.75Z' stroke='#000' fill='none' stroke-width='.3985' stroke-miterlimit='10'/>
<text class='f2' x='72.696413' y='73.475155' transform='matrix(1 0 0 1 -142.7057 45.9238)'>14</text>
<text class='f1' x='82.659091' y='73.475155' transform='matrix(1 0 0 1 -142.7057 45.9238)'>.</text>
<text class='f2' x='85.4265' y='73.475155' transform='matrix(1 0 0 1 -142.7057 45.9238)'>8</text>
<text class='f1' x='90.407839' y='73.475155' transform='matrix(1 0 0 1 -142.7057 45.9238)'>V</text>
<text class='f0' x='72.696413' y='73.475155' transform='matrix(1 0 0 1 -124.6559 59.1848)'></text>
<path d='M-30.4846 101.8203H-28.1056C-28.1056 100.9453-27.3946 100.2344-26.5156 100.2344C-25.6406 100.2344-24.9297 100.9453-24.9297 101.8203H-22.5508M-26.5156 97.8555V99.8359M-26.5156 100.6328V105.7891' stroke='#000' fill='none' stroke-width='.3985' stroke-miterlimit='10' stroke-linejoin='bevel'/>
<path d='M-12.3438-28.9728L-6.3906-26.9098L-18.2969-23.5781L-6.3906-20.25L-18.2969-16.9219L-6.3906-13.5898L-18.2969-10.2617L-6.3906-6.9336L-18.2969-3.6055L-6.3906-.2734L-18.2969 3.0547L-6.3906 6.3828L-18.2969 9.7148L-6.3906 13.043L-18.2969 16.3711L-6.3906 19.6992L-18.2969 23.0313L-6.3906 26.3594L-18.2969 29.6875L-12.3438 31.3516' stroke='#000' fill='none' stroke-width='.797' stroke-miterlimit='10' stroke-linejoin='bevel'/>
<path d='M3.5312 1.1914H-3.2813' stroke='#000' fill='none' stroke-width='.797' stroke-miterlimit='10' stroke-linejoin='bevel'/>
<path d='M-6.39063 1.191406C-5.09766 1.449218-2.765626 1.968749-1.21094 3.13281C-2.503907 1.707031-2.503907 .671874-1.21094-.75C-2.765626 .414062-5.09766 .933593-6.39063 1.191406Z'/>
<text class='f2' x='72.696413' y='73.475155' transform='matrix(1 0 0 1 -65.97014 -70.13967)'>30<tspan x='84.319491'></tspan></text>
<path d='M-24.9297 130.168C-24.9297 129.293-25.6406 128.582-26.5156 128.582C-27.3946 128.582-28.1056 129.293-28.1056 130.168C-28.1056 131.0469-27.3946 131.7578-26.5156 131.7578C-25.6406 131.7578-24.9297 131.0469-24.9297 130.168Z'/>
<path d='M-24.9297 130.168C-24.9297 129.293-25.6406 128.582-26.5156 128.582C-27.3946 128.582-28.1056 129.293-28.1056 130.168C-28.1056 131.0469-27.3946 131.7578-26.5156 131.7578C-25.6406 131.7578-24.9297 131.0469-24.9297 130.168Z' stroke='#000' fill='none' stroke-width='.3985' stroke-miterlimit='10'/>
<path d='M-10.7578-34.2418C-10.7578-35.1208-11.4688-35.8278-12.3438-35.8278S-13.9297-35.1208-13.9297-34.2418C-13.9297-33.3668-13.2188-32.6558-12.3438-32.6558S-10.7578-33.3668-10.7578-34.2418Z'/>
<path d='M-10.7578-34.2418C-10.7578-35.1208-11.4688-35.8278-12.3438-35.8278S-13.9297-35.1208-13.9297-34.2418C-13.9297-33.3668-13.2188-32.6558-12.3438-32.6558S-10.7578-33.3668-10.7578-34.2418Z' stroke='#000' fill='none' stroke-width='.3985' stroke-miterlimit='10'/>
<path d='M171.9102 47.2266L165.957 44.1484L177.8634 38.793L165.957 33.4336L177.8634 28.0781L165.957 22.7188L177.8634 17.3594L171.9102 14.6836' stroke='#000' fill='none' stroke-width='.797' stroke-miterlimit='10' stroke-linejoin='bevel'/>
<text class='f2' x='72.696413' y='73.475155' transform='matrix(1 0 0 1 69.4716 -40.3754)'>6</text>
<text class='f1' x='77.677752' y='73.475155' transform='matrix(1 0 0 1 69.4716 -40.3754)'>.</text>
<text class='f2' x='80.445161' y='73.475155' transform='matrix(1 0 0 1 69.4716 -40.3754)'>8<tspan x='87.086899'></tspan></text>
<path d='M203.3754-2.2109V21.6016M211.3124-2.2109V21.6016' stroke='#000' fill='none' stroke-width='.797' stroke-miterlimit='10'/>
<text class='f2' x='72.696413' y='73.475155' transform='matrix(1 0 0 1 122.7806 -80.09378)'>22</text>
<text class='f1' x='82.659091' y='73.475155' transform='matrix(1 0 0 1 122.7806 -80.09378)'>nF</text>
<path d='M242.7774 14.6836L248.7304 17.7578L236.8244 23.1172L248.7304 28.4766L236.8244 33.832L248.7304 39.1914L236.8244 44.5469L242.7774 47.2266' stroke='#000' fill='none' stroke-width='.797' stroke-miterlimit='10' stroke-linejoin='bevel'/>
<text class='f2' x='72.696413' y='73.475155' transform='matrix(1 0 0 1 178.2376 -40.3754)'>6</text>
<text class='f1' x='77.677752' y='73.475155' transform='matrix(1 0 0 1 178.2376 -40.3754)'>.</text>
<text class='f2' x='80.445161' y='73.475155' transform='matrix(1 0 0 1 178.2376 -40.3754)'>8<tspan x='87.086899'></tspan></text>
<path d='M187.6714 9.6953C187.6714 8.8164 186.9614 8.1094 186.0824 8.1094C185.2074 8.1094 184.4964 8.8164 184.4964 9.6953C184.4964 10.5703 185.2074 11.2813 186.0824 11.2813C186.9614 11.2813 187.6714 10.5703 187.6714 9.6953Z'/>
<path d='M187.6714 9.6953C187.6714 8.8164 186.9614 8.1094 186.0824 8.1094C185.2074 8.1094 184.4964 8.8164 184.4964 9.6953C184.4964 10.5703 185.2074 11.2813 186.0824 11.2813C186.9614 11.2813 187.6714 10.5703 187.6714 9.6953Z' stroke='#000' fill='none' stroke-width='.3985' stroke-miterlimit='10'/>
<path d='M223.2184 43.9961V32.0898H191.4684V43.9961Z' clip-path='url(#clip1)' fill-rule='evenodd'/>
<path d='M223.2184 43.9961V32.0898H191.4684V43.9961Z' stroke='#000' fill='none' stroke-width='.797' stroke-miterlimit='10' clip-path='url(#clip1)'/>
<path d='M207.3434 49.9492C213.9184 49.9492 219.2504 44.6172 219.2504 38.043C219.2504 31.4648 213.9184 26.1367 207.3434 26.1367C200.7694 26.1367 195.4374 31.4648 195.4374 38.043C195.4374 44.6172 200.7694 49.9492 207.3434 49.9492Z' fill='#fff'/>
<path d='M207.3434 49.9492C213.9184 49.9492 219.2504 44.6172 219.2504 38.043C219.2504 31.4648 213.9184 26.1367 207.3434 26.1367C200.7694 26.1367 195.4374 31.4648 195.4374 38.043C195.4374 44.6172 200.7694 49.9492 207.3434 49.9492Z' stroke='#000' fill='none' stroke-width='.797' stroke-miterlimit='10'/>
<text class='f2' x='72.696413' y='73.475155' transform='matrix(1 0 0 1 130.0806 -32.0295)'>M</text>
<path d='M230.1914 9.6953C230.1914 8.8164 229.4804 8.1094 228.6054 8.1094C227.7264 8.1094 227.0154 8.8164 227.0154 9.6953C227.0154 10.5703 227.7264 11.2813 228.6054 11.2813C229.4804 11.2813 230.1914 10.5703 230.1914 9.6953Z'/>
<path d='M230.1914 9.6953C230.1914 8.8164 229.4804 8.1094 228.6054 8.1094C227.7264 8.1094 227.0154 8.8164 227.0154 9.6953C227.0154 10.5703 227.7264 11.2813 228.6054 11.2813C229.4804 11.2813 230.1914 10.5703 230.1914 9.6953Z' stroke='#000' fill='none' stroke-width='.3985' stroke-miterlimit='10'/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 220 KiB

54
filters.py Normal file
View File

@ -0,0 +1,54 @@
def add_lightboxes(html: str,
lightbox_class: str = "lightbox",
wrapper_class: str = "lightbox-wrapper") -> str:
counter: int = 0
img_start: int = html.find("<img")
while img_start > -1:
counter += 1
img_end: int = html.find(">", img_start + 4)
lightbox: str = f"<span id=\"fig{counter}\"></span>\n" +\
f"<figure id=\"figure{counter}\">\n" +\
f" <a href=\"#figure{counter}\">\n" +\
f" {html[img_start:img_end + 1]}\n" +\
f" </a>\n"
alt_start: int = html.find("alt=\"", img_start + 4)
if alt_start > -1:
alt_end: int = html.find("\"", alt_start + 5)
lightbox = lightbox + f" <figcaption>\n" +\
f" {html[alt_start + 5:alt_end]}\n" +\
f" </figcaption>\n"
lightbox = lightbox + f" <div class=\"{lightbox_class}\">\n" +\
f" <div class=\"{wrapper_class}\">\n" +\
f" <a href=\"#fig{counter}\">\n" +\
f" [close]\n" +\
f" </a>\n" +\
f" {html[img_start:img_end + 1]}\n" +\
f" </div>\n" +\
f" </div>\n" +\
f"</figure>\n"
if html[img_start - 3:img_start] == "<p>" and html[img_end + 1:img_end + 5] == "</p>":
img_start -= 3
img_end += 4
html = html[:img_start] + lightbox + html[img_end + 1:]
img_start = html.find("<img", img_start + len(lightbox))
return html
def add_sidenotes(html: str,
toggle_class: str = "sidenote-toggle",
label_class: str = "sidenote-number",
sidenote_class: str = "sidenote") -> str:
counter: int = 0
start: int = html.find("")
while start > -1:
counter += 1
end: int = html.find("]", start)
text: str = html[start + 2:end]
sidenote: str = f"<label for=\"sn-{counter}\" class=\"{toggle_class} {label_class}\"></label>\n" +\
f"<input type=\"checkbox\" id=\"sn-{counter}\" class=\"{toggle_class}\" />\n" +\
f"<span class=\"{sidenote_class}\">\n" +\
f" {text}\n" +\
f"</span>\n"
html = html[:start] + sidenote + html[end + 1:]
start = html.find("", start + len(sidenote))
return html

53
pelicanconf.py Normal file
View File

@ -0,0 +1,53 @@
from sys import path
from os import curdir
path.append(curdir)
from filters import add_lightboxes, add_sidenotes
AUTHOR = 'Error'
SITENAME = 'Undefined Behavior'
SITEURL = ''
ABSTRACT = "If, as Adam Savage famously put it, the only difference between screwing around and science is writing it down, I should probably write about my projects somewhere. I'll just do it here."
FAVICON = 'favicon.svg'
STATIC_PATHS = ['favicon.svg']
TIMEZONE = 'Europe/Rome'
DEFAULT_DATE_FORMAT = '%Y-%m-%d'
DEFAULT_LANG = 'en'
THEME = 'undefined-pelican-theme'
PATH = 'content'
ARTICLE_URL = 'posts/{slug}/'
ARTICLE_SAVE_AS = 'posts/{slug}/index.html'
PAGE_URL = 'pages/{slug}/'
PAGE_SAVE_AS = 'pages/{slug}/index.html'
AUTHOR_URL = ''
AUTHOR_SAVE_AS = ''
AUTHORS_SAVE_AS = ''
CATEGORY_URL = ''
CATEGORY_SAVE_AS = ''
CATEGORIES_SAVE_AS = ''
TAG_URL = ''
TAG_SAVE_AS = ''
TAGS_SAVE_AS = ''
ARCHIVES_SAVE_AS = ''
# Feed generation settings
FEED_ALL_ATOM = 'feeds/atom.xml'
CATEGORY_FEED_ATOM = None
TRANSLATION_FEED_ATOM = None
AUTHOR_FEED_ATOM = None
AUTHOR_FEED_RSS = None
LINKS = (('credits', '/pages/credits'),
('imprint', '/pages/imprint'),
('privacy', '/pages/privacy'),)
DEFAULT_PAGINATION = False
# dev settings
RELATIVE_URLS = True
DELETE_OUTPUT_DIRECTORY = True
JINJA_FILTERS = {'add_lightboxes': add_lightboxes,
'add_sidenotes': add_sidenotes}

9
publishconf.py Normal file
View File

@ -0,0 +1,9 @@
from sys import path
from os import curdir
path.append(curdir)
from pelicanconf import *
SITEURL = 'https://undefinedbehavior.de'
PATH = '/var/www/virtual/undef/html'
RELATIVE_URLS = False